Commit 0529a7ad authored by Mark A. Greer's avatar Mark A. Greer Committed by Samuel Ortiz

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: default avatarThierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: default avatarMark A. Greer <mgreer@animalcreek.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 4b4dbca5
...@@ -299,6 +299,7 @@ int digital_target_found(struct nfc_digital_dev *ddev, ...@@ -299,6 +299,7 @@ int digital_target_found(struct nfc_digital_dev *ddev,
int rc; int rc;
u8 framing; u8 framing;
u8 rf_tech; u8 rf_tech;
u8 poll_tech_count;
int (*check_crc)(struct sk_buff *skb); int (*check_crc)(struct sk_buff *skb);
void (*add_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, ...@@ -375,12 +376,16 @@ int digital_target_found(struct nfc_digital_dev *ddev,
return rc; return rc;
target->supported_protocols = (1 << protocol); 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; 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; return 0;
} }
......
...@@ -673,6 +673,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, ...@@ -673,6 +673,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
int rc; int rc;
struct digital_atr_req *atr_req; struct digital_atr_req *atr_req;
size_t gb_len, min_size; size_t gb_len, min_size;
u8 poll_tech_count;
if (IS_ERR(resp)) { if (IS_ERR(resp)) {
rc = PTR_ERR(resp); rc = PTR_ERR(resp);
...@@ -730,12 +731,16 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg, ...@@ -730,12 +731,16 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
goto exit; goto exit;
gb_len = resp->len - sizeof(struct digital_atr_req); 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, rc = nfc_tm_activated(ddev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
NFC_COMM_PASSIVE, atr_req->gb, gb_len); NFC_COMM_PASSIVE, atr_req->gb, gb_len);
if (rc) if (rc) {
ddev->poll_tech_count = poll_tech_count;
goto exit; goto exit;
}
ddev->poll_tech_count = 0;
rc = 0; rc = 0;
exit: exit:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment