diff options
author | Mark A. Greer <mgreer@animalcreek.com> | 2014-09-23 19:38:14 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-11-28 06:40:38 -0500 |
commit | 9b5ec0fd584df424c0541f631b7c1154697bf227 (patch) | |
tree | 69d7d946aae64c29846434d944987da74854f251 | |
parent | 384ab1d174a11292af63674a26eaa99864db9b48 (diff) |
NFC: digital: Add NFC-DEP Target-side ATN Support
When an NFC-DEP target receives an ATN PDU, its
supposed to respond with a similar ATN PDU.
When the Target receives an I PDU with the PNI
one less than the current PNI and the last PDU
sent was an ATN PDU, the Target is to resend the
last non-ATN PDU that it has sent. This is
described in section 14.12.3.4 of the NFC Digital
Protocol Spec.
The digital layer's NFC-DEP code doesn't implement
this so add that support.
Reviewed-by: Thierry Escande <thierry.escande@linux.intel.com>
Tested-by: Thierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: Mark A. Greer <mgreer@animalcreek.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r-- | net/nfc/digital_dep.c | 88 |
1 files changed, 83 insertions, 5 deletions
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index 8f1fefd2ed14..f72be7433df3 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c | |||
@@ -970,6 +970,43 @@ static int digital_tg_send_ack(struct nfc_digital_dev *ddev, | |||
970 | return rc; | 970 | return rc; |
971 | } | 971 | } |
972 | 972 | ||
973 | static int digital_tg_send_atn(struct nfc_digital_dev *ddev) | ||
974 | { | ||
975 | struct digital_dep_req_res *dep_res; | ||
976 | struct sk_buff *skb; | ||
977 | int rc; | ||
978 | |||
979 | skb = digital_skb_alloc(ddev, 1); | ||
980 | if (!skb) | ||
981 | return -ENOMEM; | ||
982 | |||
983 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
984 | |||
985 | dep_res = (struct digital_dep_req_res *)skb->data; | ||
986 | |||
987 | dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; | ||
988 | dep_res->cmd = DIGITAL_CMD_DEP_RES; | ||
989 | dep_res->pfb = DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU; | ||
990 | |||
991 | if (ddev->did) { | ||
992 | dep_res->pfb |= DIGITAL_NFC_DEP_PFB_DID_BIT; | ||
993 | |||
994 | memcpy(skb_put(skb, sizeof(ddev->did)), &ddev->did, | ||
995 | sizeof(ddev->did)); | ||
996 | } | ||
997 | |||
998 | digital_skb_push_dep_sod(ddev, skb); | ||
999 | |||
1000 | ddev->skb_add_crc(skb); | ||
1001 | |||
1002 | rc = digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req, | ||
1003 | NULL); | ||
1004 | if (rc) | ||
1005 | kfree_skb(skb); | ||
1006 | |||
1007 | return rc; | ||
1008 | } | ||
1009 | |||
973 | static int digital_tg_send_saved_skb(struct nfc_digital_dev *ddev) | 1010 | static int digital_tg_send_saved_skb(struct nfc_digital_dev *ddev) |
974 | { | 1011 | { |
975 | skb_get(ddev->saved_skb); | 1012 | skb_get(ddev->saved_skb); |
@@ -1049,12 +1086,24 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | |||
1049 | case DIGITAL_NFC_DEP_PFB_I_PDU: | 1086 | case DIGITAL_NFC_DEP_PFB_I_PDU: |
1050 | pr_debug("DIGITAL_NFC_DEP_PFB_I_PDU\n"); | 1087 | pr_debug("DIGITAL_NFC_DEP_PFB_I_PDU\n"); |
1051 | 1088 | ||
1052 | if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) { | 1089 | if ((ddev->atn_count && (DIGITAL_NFC_DEP_PFB_PNI(pfb - 1) != |
1090 | ddev->curr_nfc_dep_pni)) || | ||
1091 | (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni)) { | ||
1053 | PROTOCOL_ERR("14.12.3.4"); | 1092 | PROTOCOL_ERR("14.12.3.4"); |
1054 | rc = -EIO; | 1093 | rc = -EIO; |
1055 | goto exit; | 1094 | goto exit; |
1056 | } | 1095 | } |
1057 | 1096 | ||
1097 | if (ddev->atn_count) { | ||
1098 | ddev->atn_count = 0; | ||
1099 | |||
1100 | rc = digital_tg_send_saved_skb(ddev); | ||
1101 | if (rc) | ||
1102 | goto exit; | ||
1103 | |||
1104 | return; | ||
1105 | } | ||
1106 | |||
1058 | kfree_skb(ddev->saved_skb); | 1107 | kfree_skb(ddev->saved_skb); |
1059 | ddev->saved_skb = NULL; | 1108 | ddev->saved_skb = NULL; |
1060 | 1109 | ||
@@ -1077,13 +1126,26 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | |||
1077 | break; | 1126 | break; |
1078 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: | 1127 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: |
1079 | if (!DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { /* ACK */ | 1128 | if (!DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { /* ACK */ |
1080 | if ((DIGITAL_NFC_DEP_PFB_PNI(pfb) != | 1129 | if ((ddev->atn_count && |
1130 | (DIGITAL_NFC_DEP_PFB_PNI(pfb - 1) != | ||
1131 | ddev->curr_nfc_dep_pni)) || | ||
1132 | (DIGITAL_NFC_DEP_PFB_PNI(pfb) != | ||
1081 | ddev->curr_nfc_dep_pni) || | 1133 | ddev->curr_nfc_dep_pni) || |
1082 | !ddev->chaining_skb || !ddev->saved_skb) { | 1134 | !ddev->chaining_skb || !ddev->saved_skb) { |
1083 | rc = -EIO; | 1135 | rc = -EIO; |
1084 | goto exit; | 1136 | goto exit; |
1085 | } | 1137 | } |
1086 | 1138 | ||
1139 | if (ddev->atn_count) { | ||
1140 | ddev->atn_count = 0; | ||
1141 | |||
1142 | rc = digital_tg_send_saved_skb(ddev); | ||
1143 | if (rc) | ||
1144 | goto exit; | ||
1145 | |||
1146 | return; | ||
1147 | } | ||
1148 | |||
1087 | kfree_skb(ddev->saved_skb); | 1149 | kfree_skb(ddev->saved_skb); |
1088 | ddev->saved_skb = NULL; | 1150 | ddev->saved_skb = NULL; |
1089 | 1151 | ||
@@ -1098,6 +1160,8 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | |||
1098 | goto exit; | 1160 | goto exit; |
1099 | } | 1161 | } |
1100 | 1162 | ||
1163 | ddev->atn_count = 0; | ||
1164 | |||
1101 | rc = digital_tg_send_saved_skb(ddev); | 1165 | rc = digital_tg_send_saved_skb(ddev); |
1102 | if (rc) { | 1166 | if (rc) { |
1103 | kfree_skb(ddev->saved_skb); | 1167 | kfree_skb(ddev->saved_skb); |
@@ -1107,9 +1171,19 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | |||
1107 | 1171 | ||
1108 | return; | 1172 | return; |
1109 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: | 1173 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: |
1110 | pr_err("Received a SUPERVISOR PDU\n"); | 1174 | if (DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { |
1111 | rc = -EINVAL; | 1175 | rc = -EINVAL; |
1112 | goto exit; | 1176 | goto exit; |
1177 | } | ||
1178 | |||
1179 | rc = digital_tg_send_atn(ddev); | ||
1180 | if (rc) | ||
1181 | goto exit; | ||
1182 | |||
1183 | ddev->atn_count++; | ||
1184 | |||
1185 | kfree_skb(resp); | ||
1186 | return; | ||
1113 | } | 1187 | } |
1114 | 1188 | ||
1115 | rc = nfc_tm_data_received(ddev->nfc_dev, resp); | 1189 | rc = nfc_tm_data_received(ddev->nfc_dev, resp); |
@@ -1118,6 +1192,8 @@ exit: | |||
1118 | kfree_skb(ddev->chaining_skb); | 1192 | kfree_skb(ddev->chaining_skb); |
1119 | ddev->chaining_skb = NULL; | 1193 | ddev->chaining_skb = NULL; |
1120 | 1194 | ||
1195 | ddev->atn_count = 0; | ||
1196 | |||
1121 | kfree_skb(ddev->saved_skb); | 1197 | kfree_skb(ddev->saved_skb); |
1122 | ddev->saved_skb = NULL; | 1198 | ddev->saved_skb = NULL; |
1123 | 1199 | ||
@@ -1311,6 +1387,8 @@ static void digital_tg_send_atr_res_complete(struct nfc_digital_dev *ddev, | |||
1311 | if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) | 1387 | if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) |
1312 | offset++; | 1388 | offset++; |
1313 | 1389 | ||
1390 | ddev->atn_count = 0; | ||
1391 | |||
1314 | if (resp->data[offset] == DIGITAL_CMD_PSL_REQ) | 1392 | if (resp->data[offset] == DIGITAL_CMD_PSL_REQ) |
1315 | digital_tg_recv_psl_req(ddev, arg, resp); | 1393 | digital_tg_recv_psl_req(ddev, arg, resp); |
1316 | else | 1394 | else |