NFC: digital: Fix target DEP_REQ I-PDU handling after ATN PDU
When the initiator sends a DEP_REQ I-PDU, the target device may not reply in a timely manner. In this case the initiator device must send an attention PDU (ATN) and if the recipient replies with an ATN PDU in return, then the last I-PDU must be sent again by the initiator. This patch fixes how the target handles I-PDU received after an ATN PDU has been received. There are 2 possible cases: - The target has received the initial DEP_REQ and sends back the DEP_RES but the initiator did not receive it. In this case, after the initiator has sent an ATN PDU and the target replied it (with an ATN as well), the initiator sends the saved skb of the initial DEP_REQ again and the target replies with the saved skb of the initial DEP_RES. - Or the target did not even received the initial DEP_REQ. In this case, after the ATN PDUs exchange, the initiator sends the saved skb and the target simply passes it up, just as usual. This behavior is controlled using the atn_count and the PNI field of the digital device structure. Signed-off-by: Thierry Escande <thierry.escande@collabora.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
e8e7f42175
commit
f23a9868b1
@ -1086,24 +1086,40 @@ 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)) {
|
||||
if (ddev->atn_count) {
|
||||
/* The target has received (and replied to) at least one
|
||||
* ATN DEP_REQ.
|
||||
*/
|
||||
ddev->atn_count = 0;
|
||||
|
||||
/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (ddev->atn_count) {
|
||||
ddev->atn_count = 0;
|
||||
|
||||
rc = digital_tg_send_saved_skb(ddev);
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
kfree_skb(ddev->saved_skb);
|
||||
ddev->saved_skb = NULL;
|
||||
|
||||
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user