diff options
author | Thierry Escande <thierry.escande@collabora.com> | 2016-07-08 09:52:42 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2016-07-10 19:58:46 -0400 |
commit | 482333b277de181ce80c833d84f2598e2527b267 (patch) | |
tree | c21195b9d804a9cf02abec6ccf3bab3db253459d | |
parent | f23a9868b1c45e77ec6082eb95508885111ffda1 (diff) |
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>
-rw-r--r-- | net/nfc/digital_dep.c | 71 |
1 files changed, 43 insertions, 28 deletions
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index 1778c23751d4..e0268777ab18 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c | |||
@@ -1141,49 +1141,64 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | |||
1141 | rc = 0; | 1141 | rc = 0; |
1142 | break; | 1142 | break; |
1143 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: | 1143 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: |
1144 | if (!DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { /* ACK */ | 1144 | if (DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { /* NACK */ |
1145 | if ((ddev->atn_count && | 1145 | if (DIGITAL_NFC_DEP_PFB_PNI(pfb + 1) != |
1146 | (DIGITAL_NFC_DEP_PFB_PNI(pfb - 1) != | 1146 | ddev->curr_nfc_dep_pni) { |
1147 | ddev->curr_nfc_dep_pni)) || | ||
1148 | (DIGITAL_NFC_DEP_PFB_PNI(pfb) != | ||
1149 | ddev->curr_nfc_dep_pni) || | ||
1150 | !ddev->chaining_skb || !ddev->saved_skb) { | ||
1151 | rc = -EIO; | 1147 | rc = -EIO; |
1152 | goto exit; | 1148 | goto exit; |
1153 | } | 1149 | } |
1154 | 1150 | ||
1155 | if (ddev->atn_count) { | 1151 | ddev->atn_count = 0; |
1156 | ddev->atn_count = 0; | 1152 | |
1153 | rc = digital_tg_send_saved_skb(ddev); | ||
1154 | if (rc) | ||
1155 | goto exit; | ||
1156 | |||
1157 | goto free_resp; | ||
1158 | } | ||
1159 | |||
1160 | /* ACK */ | ||
1161 | if (ddev->atn_count) { | ||
1162 | /* The target has previously recevied one or more ATN | ||
1163 | * PDUs. | ||
1164 | */ | ||
1165 | ddev->atn_count = 0; | ||
1157 | 1166 | ||
1167 | /* If the ACK PNI is equal to the target PNI - 1 means | ||
1168 | * that the initiator did not receive the previous PDU | ||
1169 | * sent by the target so re-send it. | ||
1170 | */ | ||
1171 | if (DIGITAL_NFC_DEP_PFB_PNI(pfb + 1) == | ||
1172 | ddev->curr_nfc_dep_pni) { | ||
1158 | rc = digital_tg_send_saved_skb(ddev); | 1173 | rc = digital_tg_send_saved_skb(ddev); |
1159 | if (rc) | 1174 | if (rc) |
1160 | goto exit; | 1175 | goto exit; |
1161 | 1176 | ||
1162 | return; | 1177 | goto free_resp; |
1163 | } | 1178 | } |
1164 | 1179 | ||
1165 | kfree_skb(ddev->saved_skb); | 1180 | /* Otherwise, the target did not receive the previous |
1166 | ddev->saved_skb = NULL; | 1181 | * ACK PDU from the initiator. Fallback to normal |
1182 | * processing of chained PDU then. | ||
1183 | */ | ||
1184 | } | ||
1167 | 1185 | ||
1168 | rc = digital_tg_send_dep_res(ddev, ddev->chaining_skb); | 1186 | /* Keep on sending chained PDU */ |
1169 | if (rc) | 1187 | if (!ddev->chaining_skb || |
1170 | goto exit; | 1188 | DIGITAL_NFC_DEP_PFB_PNI(pfb) != |
1171 | } else { /* NACK */ | 1189 | ddev->curr_nfc_dep_pni) { |
1172 | if ((DIGITAL_NFC_DEP_PFB_PNI(pfb + 1) != | 1190 | rc = -EIO; |
1173 | ddev->curr_nfc_dep_pni) || | 1191 | goto exit; |
1174 | !ddev->saved_skb) { | 1192 | } |
1175 | rc = -EIO; | ||
1176 | goto exit; | ||
1177 | } | ||
1178 | 1193 | ||
1179 | ddev->atn_count = 0; | 1194 | kfree_skb(ddev->saved_skb); |
1195 | ddev->saved_skb = NULL; | ||
1180 | 1196 | ||
1181 | rc = digital_tg_send_saved_skb(ddev); | 1197 | rc = digital_tg_send_dep_res(ddev, ddev->chaining_skb); |
1182 | if (rc) | 1198 | if (rc) |
1183 | goto exit; | 1199 | goto exit; |
1184 | } | ||
1185 | 1200 | ||
1186 | return; | 1201 | goto free_resp; |
1187 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: | 1202 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: |
1188 | if (DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { | 1203 | if (DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { |
1189 | rc = -EINVAL; | 1204 | rc = -EINVAL; |