Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFC: protect nci_data_exchange transactions

Protect 'cb' and 'cb_context' arguments in nci_data_exchange.
In fact, this implements a queue with max length of 1 data
exchange transactions in parallel.

Signed-off-by: Ilan Elias <ilane@ti.com>
Acked-by: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Ilan Elias and committed by
John W. Linville
38f04c6b de054799

+13 -2
+1
include/net/nfc/nci_core.h
··· 40 40 NCI_UP, 41 41 NCI_DISCOVERY, 42 42 NCI_POLL_ACTIVE, 43 + NCI_DATA_EXCHANGE, 43 44 }; 44 45 45 46 /* NCI timeouts */
+9 -1
net/nfc/nci/core.c
··· 453 453 void *cb_context) 454 454 { 455 455 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); 456 + int rc; 456 457 457 458 nfc_dbg("entry, target_idx %d, len %d", target_idx, skb->len); 458 459 ··· 462 461 return -EINVAL; 463 462 } 464 463 464 + if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags)) 465 + return -EBUSY; 466 + 465 467 /* store cb and context to be used on receiving data */ 466 468 ndev->data_exchange_cb = cb; 467 469 ndev->data_exchange_cb_context = cb_context; 468 470 469 - return nci_send_data(ndev, ndev->conn_id, skb); 471 + rc = nci_send_data(ndev, ndev->conn_id, skb); 472 + if (rc) 473 + clear_bit(NCI_DATA_EXCHANGE, &ndev->flags); 474 + 475 + return rc; 470 476 } 471 477 472 478 static struct nfc_ops nci_nfc_ops = {
+2
net/nfc/nci/data.c
··· 54 54 /* no waiting callback, free skb */ 55 55 kfree_skb(skb); 56 56 } 57 + 58 + clear_bit(NCI_DATA_EXCHANGE, &ndev->flags); 57 59 } 58 60 59 61 /* ----------------- NCI TX Data ----------------- */
+1 -1
net/nfc/nci/ntf.c
··· 215 215 } 216 216 217 217 /* complete the data exchange transaction, if exists */ 218 - if (ndev->data_exchange_cb) 218 + if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags)) 219 219 nci_data_exchange_complete(ndev, NULL, -EIO); 220 220 } 221 221