aboutsummaryrefslogtreecommitdiffstats
path: root/net/nfc
diff options
context:
space:
mode:
Diffstat (limited to 'net/nfc')
-rw-r--r--net/nfc/digital_dep.c108
1 files changed, 98 insertions, 10 deletions
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c
index 95a69898d5f5..b78790088b8e 100644
--- a/net/nfc/digital_dep.c
+++ b/net/nfc/digital_dep.c
@@ -34,9 +34,12 @@
34 34
35#define DIGITAL_DID_MAX 14 35#define DIGITAL_DID_MAX 14
36 36
37#define DIGITAL_LR_BITS_PAYLOAD_SIZE_254B 0x30 37#define DIGITAL_PAYLOAD_SIZE_MAX 254
38#define DIGITAL_FSL_BITS_PAYLOAD_SIZE_254B \ 38#define DIGITAL_PAYLOAD_BITS_TO_PP(s) (((s) & 0x3) << 4)
39 (DIGITAL_LR_BITS_PAYLOAD_SIZE_254B >> 4) 39#define DIGITAL_PAYLOAD_PP_TO_BITS(s) (((s) >> 4) & 0x3)
40#define DIGITAL_PAYLOAD_BITS_TO_FSL(s) ((s) & 0x3)
41#define DIGITAL_PAYLOAD_FSL_TO_BITS(s) ((s) & 0x3)
42
40#define DIGITAL_GB_BIT 0x02 43#define DIGITAL_GB_BIT 0x02
41 44
42#define DIGITAL_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0) 45#define DIGITAL_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0)
@@ -101,6 +104,32 @@ struct digital_dep_req_res {
101static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, 104static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg,
102 struct sk_buff *resp); 105 struct sk_buff *resp);
103 106
107static const u8 digital_payload_bits_map[4] = {
108 [0] = 64,
109 [1] = 128,
110 [2] = 192,
111 [3] = 254
112};
113
114static u8 digital_payload_bits_to_size(u8 payload_bits)
115{
116 if (payload_bits >= ARRAY_SIZE(digital_payload_bits_map))
117 return 0;
118
119 return digital_payload_bits_map[payload_bits];
120}
121
122static u8 digital_payload_size_to_bits(u8 payload_size)
123{
124 int i;
125
126 for (i = 0; i < ARRAY_SIZE(digital_payload_bits_map); i++)
127 if (digital_payload_bits_map[i] == payload_size)
128 return i;
129
130 return 0xff;
131}
132
104static void digital_skb_push_dep_sod(struct nfc_digital_dev *ddev, 133static void digital_skb_push_dep_sod(struct nfc_digital_dev *ddev,
105 struct sk_buff *skb) 134 struct sk_buff *skb)
106{ 135{
@@ -202,6 +231,7 @@ static int digital_in_send_psl_req(struct nfc_digital_dev *ddev,
202 struct sk_buff *skb; 231 struct sk_buff *skb;
203 struct digital_psl_req *psl_req; 232 struct digital_psl_req *psl_req;
204 int rc; 233 int rc;
234 u8 payload_size, payload_bits;
205 235
206 skb = digital_skb_alloc(ddev, sizeof(*psl_req)); 236 skb = digital_skb_alloc(ddev, sizeof(*psl_req));
207 if (!skb) 237 if (!skb)
@@ -215,7 +245,13 @@ static int digital_in_send_psl_req(struct nfc_digital_dev *ddev,
215 psl_req->cmd = DIGITAL_CMD_PSL_REQ; 245 psl_req->cmd = DIGITAL_CMD_PSL_REQ;
216 psl_req->did = 0; 246 psl_req->did = 0;
217 psl_req->brs = (0x2 << 3) | 0x2; /* 424F both directions */ 247 psl_req->brs = (0x2 << 3) | 0x2; /* 424F both directions */
218 psl_req->fsl = DIGITAL_FSL_BITS_PAYLOAD_SIZE_254B; 248
249 payload_size = min(ddev->local_payload_max, ddev->remote_payload_max);
250 payload_bits = digital_payload_size_to_bits(payload_size);
251 psl_req->fsl = DIGITAL_PAYLOAD_BITS_TO_FSL(payload_bits);
252
253 ddev->local_payload_max = payload_size;
254 ddev->remote_payload_max = payload_size;
219 255
220 digital_skb_push_dep_sod(ddev, skb); 256 digital_skb_push_dep_sod(ddev, skb);
221 257
@@ -234,7 +270,7 @@ static void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg,
234{ 270{
235 struct nfc_target *target = arg; 271 struct nfc_target *target = arg;
236 struct digital_atr_res *atr_res; 272 struct digital_atr_res *atr_res;
237 u8 gb_len; 273 u8 gb_len, payload_bits;
238 int rc; 274 int rc;
239 275
240 if (IS_ERR(resp)) { 276 if (IS_ERR(resp)) {
@@ -264,6 +300,14 @@ static void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg,
264 300
265 atr_res = (struct digital_atr_res *)resp->data; 301 atr_res = (struct digital_atr_res *)resp->data;
266 302
303 payload_bits = DIGITAL_PAYLOAD_PP_TO_BITS(atr_res->pp);
304 ddev->remote_payload_max = digital_payload_bits_to_size(payload_bits);
305
306 if (!ddev->remote_payload_max) {
307 rc = -EINVAL;
308 goto exit;
309 }
310
267 rc = nfc_set_remote_general_bytes(ddev->nfc_dev, atr_res->gb, gb_len); 311 rc = nfc_set_remote_general_bytes(ddev->nfc_dev, atr_res->gb, gb_len);
268 if (rc) 312 if (rc)
269 goto exit; 313 goto exit;
@@ -295,6 +339,7 @@ int digital_in_send_atr_req(struct nfc_digital_dev *ddev,
295 struct digital_atr_req *atr_req; 339 struct digital_atr_req *atr_req;
296 uint size; 340 uint size;
297 int rc; 341 int rc;
342 u8 payload_bits;
298 343
299 size = DIGITAL_ATR_REQ_MIN_SIZE + gb_len; 344 size = DIGITAL_ATR_REQ_MIN_SIZE + gb_len;
300 345
@@ -323,7 +368,9 @@ int digital_in_send_atr_req(struct nfc_digital_dev *ddev,
323 atr_req->bs = 0; 368 atr_req->bs = 0;
324 atr_req->br = 0; 369 atr_req->br = 0;
325 370
326 atr_req->pp = DIGITAL_LR_BITS_PAYLOAD_SIZE_254B; 371 ddev->local_payload_max = DIGITAL_PAYLOAD_SIZE_MAX;
372 payload_bits = digital_payload_size_to_bits(ddev->local_payload_max);
373 atr_req->pp = DIGITAL_PAYLOAD_BITS_TO_PP(payload_bits);
327 374
328 if (gb_len) { 375 if (gb_len) {
329 atr_req->pp |= DIGITAL_GB_BIT; 376 atr_req->pp |= DIGITAL_GB_BIT;
@@ -403,6 +450,11 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg,
403 goto exit; 450 goto exit;
404 } 451 }
405 452
453 if (resp->len > ddev->local_payload_max) {
454 rc = -EMSGSIZE;
455 goto exit;
456 }
457
406 size = sizeof(struct digital_dep_req_res); 458 size = sizeof(struct digital_dep_req_res);
407 dep_res = (struct digital_dep_req_res *)resp->data; 459 dep_res = (struct digital_dep_req_res *)resp->data;
408 460
@@ -498,6 +550,9 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev,
498 550
499 skb_push(skb, sizeof(struct digital_dep_req_res)); 551 skb_push(skb, sizeof(struct digital_dep_req_res));
500 552
553 if (skb->len > ddev->remote_payload_max)
554 return -EMSGSIZE;
555
501 dep_req = (struct digital_dep_req_res *)skb->data; 556 dep_req = (struct digital_dep_req_res *)skb->data;
502 dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; 557 dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT;
503 dep_req->cmd = DIGITAL_CMD_DEP_REQ; 558 dep_req->cmd = DIGITAL_CMD_DEP_REQ;
@@ -564,6 +619,11 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
564 goto exit; 619 goto exit;
565 } 620 }
566 621
622 if (resp->len > ddev->local_payload_max) {
623 rc = -EMSGSIZE;
624 goto exit;
625 }
626
567 size = sizeof(struct digital_dep_req_res); 627 size = sizeof(struct digital_dep_req_res);
568 dep_req = (struct digital_dep_req_res *)resp->data; 628 dep_req = (struct digital_dep_req_res *)resp->data;
569 629
@@ -639,6 +699,10 @@ int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb)
639 struct digital_dep_req_res *dep_res; 699 struct digital_dep_req_res *dep_res;
640 700
641 skb_push(skb, sizeof(struct digital_dep_req_res)); 701 skb_push(skb, sizeof(struct digital_dep_req_res));
702
703 if (skb->len > ddev->remote_payload_max)
704 return -EMSGSIZE;
705
642 dep_res = (struct digital_dep_req_res *)skb->data; 706 dep_res = (struct digital_dep_req_res *)skb->data;
643 707
644 dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; 708 dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN;
@@ -719,7 +783,7 @@ static void digital_tg_recv_psl_req(struct nfc_digital_dev *ddev, void *arg,
719 int rc; 783 int rc;
720 struct digital_psl_req *psl_req; 784 struct digital_psl_req *psl_req;
721 u8 rf_tech; 785 u8 rf_tech;
722 u8 dsi; 786 u8 dsi, payload_size, payload_bits;
723 787
724 if (IS_ERR(resp)) { 788 if (IS_ERR(resp)) {
725 rc = PTR_ERR(resp); 789 rc = PTR_ERR(resp);
@@ -764,6 +828,18 @@ static void digital_tg_recv_psl_req(struct nfc_digital_dev *ddev, void *arg,
764 goto exit; 828 goto exit;
765 } 829 }
766 830
831 payload_bits = DIGITAL_PAYLOAD_FSL_TO_BITS(psl_req->fsl);
832 payload_size = digital_payload_bits_to_size(payload_bits);
833
834 if (!payload_size || (payload_size > min(ddev->local_payload_max,
835 ddev->remote_payload_max))) {
836 rc = -EINVAL;
837 goto exit;
838 }
839
840 ddev->local_payload_max = payload_size;
841 ddev->remote_payload_max = payload_size;
842
767 rc = digital_tg_send_psl_res(ddev, psl_req->did, rf_tech); 843 rc = digital_tg_send_psl_res(ddev, psl_req->did, rf_tech);
768 844
769exit: 845exit:
@@ -795,7 +871,7 @@ static int digital_tg_send_atr_res(struct nfc_digital_dev *ddev,
795{ 871{
796 struct digital_atr_res *atr_res; 872 struct digital_atr_res *atr_res;
797 struct sk_buff *skb; 873 struct sk_buff *skb;
798 u8 *gb; 874 u8 *gb, payload_bits;
799 size_t gb_len; 875 size_t gb_len;
800 int rc; 876 int rc;
801 877
@@ -816,7 +892,11 @@ static int digital_tg_send_atr_res(struct nfc_digital_dev *ddev,
816 atr_res->cmd = DIGITAL_CMD_ATR_RES; 892 atr_res->cmd = DIGITAL_CMD_ATR_RES;
817 memcpy(atr_res->nfcid3, atr_req->nfcid3, sizeof(atr_req->nfcid3)); 893 memcpy(atr_res->nfcid3, atr_req->nfcid3, sizeof(atr_req->nfcid3));
818 atr_res->to = 8; 894 atr_res->to = 8;
819 atr_res->pp = DIGITAL_LR_BITS_PAYLOAD_SIZE_254B; 895
896 ddev->local_payload_max = DIGITAL_PAYLOAD_SIZE_MAX;
897 payload_bits = digital_payload_size_to_bits(ddev->local_payload_max);
898 atr_res->pp = DIGITAL_PAYLOAD_BITS_TO_PP(payload_bits);
899
820 if (gb_len) { 900 if (gb_len) {
821 skb_put(skb, gb_len); 901 skb_put(skb, gb_len);
822 902
@@ -844,7 +924,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
844 int rc; 924 int rc;
845 struct digital_atr_req *atr_req; 925 struct digital_atr_req *atr_req;
846 size_t gb_len, min_size; 926 size_t gb_len, min_size;
847 u8 poll_tech_count; 927 u8 poll_tech_count, payload_bits;
848 928
849 if (IS_ERR(resp)) { 929 if (IS_ERR(resp)) {
850 rc = PTR_ERR(resp); 930 rc = PTR_ERR(resp);
@@ -893,6 +973,14 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
893 goto exit; 973 goto exit;
894 } 974 }
895 975
976 payload_bits = DIGITAL_PAYLOAD_PP_TO_BITS(atr_req->pp);
977 ddev->remote_payload_max = digital_payload_bits_to_size(payload_bits);
978
979 if (!ddev->remote_payload_max) {
980 rc = -EINVAL;
981 goto exit;
982 }
983
896 ddev->did = atr_req->did; 984 ddev->did = atr_req->did;
897 985
898 rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, 986 rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,