NFC: digital: Fix ACK & NACK PDUs handling in target mode
When the target receives a NACK PDU, it re-sends the last sent PDU. ACK PDUs are received by the target as a reply from the initiator to chained I-PDUs. There are 3 cases to handle: - If the target has previously received 1 or more ATN PDUs and the PNI in the ACK PDU is equal to the target PNI - 1, then it means that the initiator did not received the last issued PDU from the target. In this case it re-sends this PDU. - If the target has received 1 or more ATN PDUs but the ACK PNI is not the target PNI - 1, then this means that this ACK is the reply of the previous chained I-PDU sent by the target. The target did not received it on the first attempt and it is being re-sent by the initiator. The process continues as usual. - No ATN PDU received before this ACK PDU. This is the reply of a chained I-PDU. The target keeps on processing its chained I-PDU. The code has been refactored to avoid too many indentation levels. Also, ACK and NACK PDUs were not freed. This is now fixed. Signed-off-by: Thierry Escande <thierry.escande@collabora.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
f23a9868b1
commit
482333b277
|
@ -1141,25 +1141,54 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
|
|||
rc = 0;
|
||||
break;
|
||||
case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU:
|
||||
if (!DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { /* ACK */
|
||||
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) ||
|
||||
!ddev->chaining_skb || !ddev->saved_skb) {
|
||||
if (DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { /* NACK */
|
||||
if (DIGITAL_NFC_DEP_PFB_PNI(pfb + 1) !=
|
||||
ddev->curr_nfc_dep_pni) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (ddev->atn_count) {
|
||||
ddev->atn_count = 0;
|
||||
|
||||
rc = digital_tg_send_saved_skb(ddev);
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
return;
|
||||
goto free_resp;
|
||||
}
|
||||
|
||||
/* ACK */
|
||||
if (ddev->atn_count) {
|
||||
/* The target has previously recevied one or more ATN
|
||||
* PDUs.
|
||||
*/
|
||||
ddev->atn_count = 0;
|
||||
|
||||
/* If the ACK PNI is equal to the target PNI - 1 means
|
||||
* that the initiator did not receive the previous PDU
|
||||
* sent by the target so re-send it.
|
||||
*/
|
||||
if (DIGITAL_NFC_DEP_PFB_PNI(pfb + 1) ==
|
||||
ddev->curr_nfc_dep_pni) {
|
||||
rc = digital_tg_send_saved_skb(ddev);
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
goto free_resp;
|
||||
}
|
||||
|
||||
/* Otherwise, the target did not receive the previous
|
||||
* ACK PDU from the initiator. Fallback to normal
|
||||
* processing of chained PDU then.
|
||||
*/
|
||||
}
|
||||
|
||||
/* Keep on sending chained PDU */
|
||||
if (!ddev->chaining_skb ||
|
||||
DIGITAL_NFC_DEP_PFB_PNI(pfb) !=
|
||||
ddev->curr_nfc_dep_pni) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
kfree_skb(ddev->saved_skb);
|
||||
|
@ -1168,22 +1197,8 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
|
|||
rc = digital_tg_send_dep_res(ddev, ddev->chaining_skb);
|
||||
if (rc)
|
||||
goto exit;
|
||||
} else { /* NACK */
|
||||
if ((DIGITAL_NFC_DEP_PFB_PNI(pfb + 1) !=
|
||||
ddev->curr_nfc_dep_pni) ||
|
||||
!ddev->saved_skb) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ddev->atn_count = 0;
|
||||
|
||||
rc = digital_tg_send_saved_skb(ddev);
|
||||
if (rc)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return;
|
||||
goto free_resp;
|
||||
case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU:
|
||||
if (DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) {
|
||||
rc = -EINVAL;
|
||||
|
|
Loading…
Reference in New Issue