NFC: digital: Clear poll_tech_count before activating target
authorMark A. Greer <mgreer@animalcreek.com>
Wed, 2 Jul 2014 16:03:49 +0000 (09:03 -0700)
committerSamuel Ortiz <sameo@linux.intel.com>
Sun, 20 Jul 2014 22:45:11 +0000 (00:45 +0200)
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>
net/nfc/digital_core.c
net/nfc/digital_dep.c

index a6ce3c627e4e40ff4a6fcdb0bb0a2704dd0872b0..361bc37d2db1953aa9aba7d61553c4838a826686 100644 (file)
@@ -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;
 }
 
index 171cb9949ab58560bc3d1c997d963e2928cf5aa5..7cc1830633ccbb8e3fda9f38490f90225513f572 100644 (file)
@@ -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: