diff options
author | Mark A. Greer <mgreer@animalcreek.com> | 2014-07-02 20:03:49 +0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-07-21 02:45:11 +0400 |
commit | 0529a7adf3421acf251355444a012073abaffebc (patch) | |
tree | 6aee9b69ddc4bb59f559197575eba606f532334f /net/nfc | |
parent | 4b4dbca5e49eea2567d0da777fea2c86e7b89622 (diff) | |
download | linux-0529a7adf3421acf251355444a012073abaffebc.tar.xz |
NFC: digital: Clear poll_tech_count before activating target
Currently, digital_target_found() has a race between
the events started by calling nfc_targets_found()
(which ultimately expect ddev->poll_tech_count to be
zero) and setting ddev->poll_tech_count to zero after
the call to nfc_targets_found(). When the race is
"lost" (i.e., ddev->poll_tech_count is found to not
be zero by the events started by nfc_targets_found()),
an error message is printed and the target is not found.
A similar race exists when digital_tg_recv_atr_req()
calls nfc_tm_activated().
Fix this by first saving the current value of
ddev->poll_tech_count and then clearing it before
calling nfc_targets_found()/nfc_tm_activated().
Clearing ddev->poll_tech_count before calling
nfc_targets_found()/nfc_tm_activated() eliminates
the race. Saving the value is required so it can be
restored when nfc_targets_found()/nfc_tm_activated()
fails and polling needs to continue.
Acked-by: Thierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/digital_core.c | 11 | ||||
-rw-r--r-- | net/nfc/digital_dep.c | 11 |
2 files changed, 16 insertions, 6 deletions
diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index a6ce3c627e4e..361bc37d2db1 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c @@ -299,6 +299,7 @@ int digital_target_found(struct nfc_digital_dev *ddev, int rc; u8 framing; u8 rf_tech; + u8 poll_tech_count; int (*check_crc)(struct sk_buff *skb); void (*add_crc)(struct sk_buff *skb); @@ -375,12 +376,16 @@ int digital_target_found(struct nfc_digital_dev *ddev, return rc; target->supported_protocols = (1 << protocol); - rc = nfc_targets_found(ddev->nfc_dev, target, 1); - if (rc) - return rc; + poll_tech_count = ddev->poll_tech_count; ddev->poll_tech_count = 0; + rc = nfc_targets_found(ddev->nfc_dev, target, 1); + if (rc) { + ddev->poll_tech_count = poll_tech_count; + return rc; + } + return 0; } diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index 171cb9949ab5..7cc1830633cc 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c @@ -673,6 +673,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, int rc; struct digital_atr_req *atr_req; size_t gb_len, min_size; + u8 poll_tech_count; if (IS_ERR(resp)) { rc = PTR_ERR(resp); @@ -730,12 +731,16 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, goto exit; gb_len = resp->len - sizeof(struct digital_atr_req); + + poll_tech_count = ddev->poll_tech_count; + ddev->poll_tech_count = 0; + rc = nfc_tm_activated(ddev->nfc_dev, NFC_PROTO_NFC_DEP_MASK, NFC_COMM_PASSIVE, atr_req->gb, gb_len); - if (rc) + if (rc) { + ddev->poll_tech_count = poll_tech_count; goto exit; - - ddev->poll_tech_count = 0; + } rc = 0; exit: |