aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Escande <thierry.escande@collabora.com>2016-07-08 09:52:42 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2016-07-10 19:58:46 -0400
commit482333b277de181ce80c833d84f2598e2527b267 (patch)
treec21195b9d804a9cf02abec6ccf3bab3db253459d
parentf23a9868b1c45e77ec6082eb95508885111ffda1 (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.c71
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;