diff options
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/digital_dep.c | 45 |
1 files changed, 33 insertions, 12 deletions
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index ed3a52971d65..1778c23751d4 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c @@ -1086,22 +1086,38 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, case DIGITAL_NFC_DEP_PFB_I_PDU: pr_debug("DIGITAL_NFC_DEP_PFB_I_PDU\n"); - if ((ddev->atn_count && (DIGITAL_NFC_DEP_PFB_PNI(pfb - 1) != - ddev->curr_nfc_dep_pni)) || - (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni)) { - PROTOCOL_ERR("14.12.3.4"); - rc = -EIO; - goto exit; - } - if (ddev->atn_count) { + /* The target has received (and replied to) at least one + * ATN DEP_REQ. + */ ddev->atn_count = 0; - rc = digital_tg_send_saved_skb(ddev); - if (rc) - goto exit; + /* pni of resp PDU equal to the target current pni - 1 + * means resp is the previous DEP_REQ PDU received from + * the initiator so the target replies with saved_skb + * which is the previous DEP_RES saved in + * digital_tg_send_dep_res(). + */ + if (DIGITAL_NFC_DEP_PFB_PNI(pfb) == + DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni - 1)) { + rc = digital_tg_send_saved_skb(ddev); + if (rc) + goto exit; - return; + goto free_resp; + } + + /* atn_count > 0 and PDU pni != curr_nfc_dep_pni - 1 + * means the target probably did not received the last + * DEP_REQ PDU sent by the initiator. The target + * fallbacks to normal processing then. + */ + } + + if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { + PROTOCOL_ERR("14.12.3.4"); + rc = -EIO; + goto exit; } kfree_skb(ddev->saved_skb); @@ -1197,6 +1213,11 @@ exit: if (rc) kfree_skb(resp); + + return; + +free_resp: + dev_kfree_skb(resp); } int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb) |