[PATCH net 1/5] nfc: nci: don't drop data received on HCI and loopback connections
From: Joas Antonio dos Santos
Date: Thu Oct 29 2026 - 19:18:00 EST
Commit 8265a626cc14 ("nfc: nci: fix double completion race in
nci_data_exchange_complete") made nci_data_exchange_complete() drop the
received skb unless it can clear NCI_DATA_EXCHANGE. That bit is only
set by nci_transceive(), for data exchanges with a remote target on the
static RF connection.
The other users of NCI logical connections do not set it: HCI over NCI
(nci_hci_send_cmd() and friends, used by st-nci) and
nci_nfcc_loopback() send with nci_send_data() and rely on their
data_exchange_cb being called for every data packet received on their
connection. Since that commit every such packet is silently freed, so
each HCI command and each loopback request times out after
NCI_DATA_TIMEOUT. On st-nci, secure element discovery fails when the
device is brought up ("SE discovery failed") and the HCI and loopback
based vendor commands no longer work.
Seen with virtual_ncidev and an emulated NFCC: the response to the
first ANY_OPEN_PIPE command is dropped and nci_hci_dev_session_init()
returns -ETIMEDOUT.
Only claim NCI_DATA_EXCHANGE for data on the static RF connection, as
before that commit data on the other connections is always handed to
their callback.
Fixes: 8265a626cc14 ("nfc: nci: fix double completion race in nci_data_exchange_complete")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Joas Antonio dos Santos <joasantonio108@xxxxxxxxx>
Assisted-by: Yaga Agent HackerSec Claude:claude-opus-5-5
---
net/nfc/nci/data.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
index 4253edea5..76ec891a0 100644
--- a/net/nfc/nci/data.c
+++ b/net/nfc/nci/data.c
@@ -46,8 +46,13 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
timer_delete_sync(&ndev->data_timer);
clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
- /* Claim completion atomically -- both close and rx_work may race here */
- if (!test_and_clear_bit(NCI_DATA_EXCHANGE, &ndev->flags)) {
+ /* Claim completion atomically -- both close and rx_work may race here.
+ * NCI_DATA_EXCHANGE only tracks nci_transceive() on the static RF
+ * connection; data received on other logical connections (HCI over
+ * NCI, NFCC loopback) is always handed to their callback.
+ */
+ if (conn_id == NCI_STATIC_RF_CONN_ID &&
+ !test_and_clear_bit(NCI_DATA_EXCHANGE, &ndev->flags)) {
kfree_skb(skb);
return;
}
--
2.43.0