summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark A. Greer <mgreer@animalcreek.com>2014-07-02 09:03:49 -0700
committerSamuel Ortiz <sameo@linux.intel.com>2014-07-21 00:45:11 +0200
commit0529a7adf3421acf251355444a012073abaffebc (patch)
tree6aee9b69ddc4bb59f559197575eba606f532334f
parent4b4dbca5e49eea2567d0da777fea2c86e7b89622 (diff)
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>
-rw-r--r--net/nfc/digital_core.c11
-rw-r--r--net/nfc/digital_dep.c11
2 files changed, 16 insertions, 6 deletions
diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c
index a6ce3c627e4..361bc37d2db 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 171cb9949ab..7cc1830633c 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: