diff options
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/digital_dep.c | 180 |
1 files changed, 174 insertions, 6 deletions
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index e613c294e426..35a9edf0e360 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c | |||
@@ -109,6 +109,8 @@ struct digital_dep_req_res { | |||
109 | 109 | ||
110 | static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | 110 | static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, |
111 | struct sk_buff *resp); | 111 | struct sk_buff *resp); |
112 | static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | ||
113 | struct sk_buff *resp); | ||
112 | 114 | ||
113 | static const u8 digital_payload_bits_map[4] = { | 115 | static const u8 digital_payload_bits_map[4] = { |
114 | [0] = 64, | 116 | [0] = 64, |
@@ -201,6 +203,72 @@ digital_send_dep_data_prep(struct nfc_digital_dev *ddev, struct sk_buff *skb, | |||
201 | return new_skb; | 203 | return new_skb; |
202 | } | 204 | } |
203 | 205 | ||
206 | static struct sk_buff * | ||
207 | digital_recv_dep_data_gather(struct nfc_digital_dev *ddev, u8 pfb, | ||
208 | struct sk_buff *resp, | ||
209 | int (*send_ack)(struct nfc_digital_dev *ddev, | ||
210 | struct digital_data_exch | ||
211 | *data_exch), | ||
212 | struct digital_data_exch *data_exch) | ||
213 | { | ||
214 | struct sk_buff *new_skb; | ||
215 | int rc; | ||
216 | |||
217 | if (DIGITAL_NFC_DEP_MI_BIT_SET(pfb) && (!ddev->chaining_skb)) { | ||
218 | ddev->chaining_skb = | ||
219 | nfc_alloc_recv_skb(8 * ddev->local_payload_max, | ||
220 | GFP_KERNEL); | ||
221 | if (!ddev->chaining_skb) { | ||
222 | rc = -ENOMEM; | ||
223 | goto error; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | if (ddev->chaining_skb) { | ||
228 | if (resp->len > skb_tailroom(ddev->chaining_skb)) { | ||
229 | new_skb = skb_copy_expand(ddev->chaining_skb, | ||
230 | skb_headroom( | ||
231 | ddev->chaining_skb), | ||
232 | 8 * ddev->local_payload_max, | ||
233 | GFP_KERNEL); | ||
234 | if (!new_skb) { | ||
235 | rc = -ENOMEM; | ||
236 | goto error; | ||
237 | } | ||
238 | |||
239 | kfree_skb(ddev->chaining_skb); | ||
240 | ddev->chaining_skb = new_skb; | ||
241 | } | ||
242 | |||
243 | memcpy(skb_put(ddev->chaining_skb, resp->len), resp->data, | ||
244 | resp->len); | ||
245 | |||
246 | kfree_skb(resp); | ||
247 | resp = NULL; | ||
248 | |||
249 | if (DIGITAL_NFC_DEP_MI_BIT_SET(pfb)) { | ||
250 | rc = send_ack(ddev, data_exch); | ||
251 | if (rc) | ||
252 | goto error; | ||
253 | |||
254 | return NULL; | ||
255 | } | ||
256 | |||
257 | resp = ddev->chaining_skb; | ||
258 | ddev->chaining_skb = NULL; | ||
259 | } | ||
260 | |||
261 | return resp; | ||
262 | |||
263 | error: | ||
264 | kfree_skb(resp); | ||
265 | |||
266 | kfree_skb(ddev->chaining_skb); | ||
267 | ddev->chaining_skb = NULL; | ||
268 | |||
269 | return ERR_PTR(rc); | ||
270 | } | ||
271 | |||
204 | static void digital_in_recv_psl_res(struct nfc_digital_dev *ddev, void *arg, | 272 | static void digital_in_recv_psl_res(struct nfc_digital_dev *ddev, void *arg, |
205 | struct sk_buff *resp) | 273 | struct sk_buff *resp) |
206 | { | 274 | { |
@@ -429,6 +497,38 @@ int digital_in_send_atr_req(struct nfc_digital_dev *ddev, | |||
429 | return rc; | 497 | return rc; |
430 | } | 498 | } |
431 | 499 | ||
500 | static int digital_in_send_ack(struct nfc_digital_dev *ddev, | ||
501 | struct digital_data_exch *data_exch) | ||
502 | { | ||
503 | struct digital_dep_req_res *dep_req; | ||
504 | struct sk_buff *skb; | ||
505 | int rc; | ||
506 | |||
507 | skb = digital_skb_alloc(ddev, 1); | ||
508 | if (!skb) | ||
509 | return -ENOMEM; | ||
510 | |||
511 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
512 | |||
513 | dep_req = (struct digital_dep_req_res *)skb->data; | ||
514 | |||
515 | dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; | ||
516 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; | ||
517 | dep_req->pfb = DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU | | ||
518 | ddev->curr_nfc_dep_pni; | ||
519 | |||
520 | digital_skb_push_dep_sod(ddev, skb); | ||
521 | |||
522 | ddev->skb_add_crc(skb); | ||
523 | |||
524 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | ||
525 | data_exch); | ||
526 | if (rc) | ||
527 | kfree_skb(skb); | ||
528 | |||
529 | return rc; | ||
530 | } | ||
531 | |||
432 | static int digital_in_send_rtox(struct nfc_digital_dev *ddev, | 532 | static int digital_in_send_rtox(struct nfc_digital_dev *ddev, |
433 | struct digital_data_exch *data_exch, u8 rtox) | 533 | struct digital_data_exch *data_exch, u8 rtox) |
434 | { | 534 | { |
@@ -534,6 +634,23 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
534 | 634 | ||
535 | ddev->curr_nfc_dep_pni = | 635 | ddev->curr_nfc_dep_pni = |
536 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); | 636 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); |
637 | |||
638 | resp = digital_recv_dep_data_gather(ddev, pfb, resp, | ||
639 | digital_in_send_ack, | ||
640 | data_exch); | ||
641 | if (IS_ERR(resp)) { | ||
642 | rc = PTR_ERR(resp); | ||
643 | resp = NULL; | ||
644 | goto error; | ||
645 | } | ||
646 | |||
647 | /* If resp is NULL then we're still chaining so return and | ||
648 | * wait for the next part of the PDU. Else, the PDU is | ||
649 | * complete so pass it up. | ||
650 | */ | ||
651 | if (!resp) | ||
652 | return; | ||
653 | |||
537 | rc = 0; | 654 | rc = 0; |
538 | break; | 655 | break; |
539 | 656 | ||
@@ -575,12 +692,6 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
575 | return; | 692 | return; |
576 | } | 693 | } |
577 | 694 | ||
578 | if (DIGITAL_NFC_DEP_MI_BIT_SET(pfb)) { | ||
579 | pr_err("MI bit set. Chained PDU not supported\n"); | ||
580 | rc = -EIO; | ||
581 | goto error; | ||
582 | } | ||
583 | |||
584 | exit: | 695 | exit: |
585 | data_exch->cb(data_exch->cb_context, resp, rc); | 696 | data_exch->cb(data_exch->cb_context, resp, rc); |
586 | 697 | ||
@@ -660,6 +771,48 @@ static void digital_tg_set_rf_tech(struct nfc_digital_dev *ddev, u8 rf_tech) | |||
660 | } | 771 | } |
661 | } | 772 | } |
662 | 773 | ||
774 | static int digital_tg_send_ack(struct nfc_digital_dev *ddev, | ||
775 | struct digital_data_exch *data_exch) | ||
776 | { | ||
777 | struct digital_dep_req_res *dep_res; | ||
778 | struct sk_buff *skb; | ||
779 | int rc; | ||
780 | |||
781 | skb = digital_skb_alloc(ddev, 1); | ||
782 | if (!skb) | ||
783 | return -ENOMEM; | ||
784 | |||
785 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
786 | |||
787 | dep_res = (struct digital_dep_req_res *)skb->data; | ||
788 | |||
789 | dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN; | ||
790 | dep_res->cmd = DIGITAL_CMD_DEP_RES; | ||
791 | dep_res->pfb = DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU | | ||
792 | ddev->curr_nfc_dep_pni; | ||
793 | |||
794 | if (ddev->did) { | ||
795 | dep_res->pfb |= DIGITAL_NFC_DEP_PFB_DID_BIT; | ||
796 | |||
797 | memcpy(skb_put(skb, sizeof(ddev->did)), &ddev->did, | ||
798 | sizeof(ddev->did)); | ||
799 | } | ||
800 | |||
801 | ddev->curr_nfc_dep_pni = | ||
802 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); | ||
803 | |||
804 | digital_skb_push_dep_sod(ddev, skb); | ||
805 | |||
806 | ddev->skb_add_crc(skb); | ||
807 | |||
808 | rc = digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req, | ||
809 | data_exch); | ||
810 | if (rc) | ||
811 | kfree_skb(skb); | ||
812 | |||
813 | return rc; | ||
814 | } | ||
815 | |||
663 | static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | 816 | static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, |
664 | struct sk_buff *resp) | 817 | struct sk_buff *resp) |
665 | { | 818 | { |
@@ -736,6 +889,21 @@ static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, | |||
736 | goto exit; | 889 | goto exit; |
737 | } | 890 | } |
738 | 891 | ||
892 | resp = digital_recv_dep_data_gather(ddev, pfb, resp, | ||
893 | digital_tg_send_ack, NULL); | ||
894 | if (IS_ERR(resp)) { | ||
895 | rc = PTR_ERR(resp); | ||
896 | resp = NULL; | ||
897 | goto exit; | ||
898 | } | ||
899 | |||
900 | /* If resp is NULL then we're still chaining so return and | ||
901 | * wait for the next part of the PDU. Else, the PDU is | ||
902 | * complete so pass it up. | ||
903 | */ | ||
904 | if (!resp) | ||
905 | return; | ||
906 | |||
739 | rc = 0; | 907 | rc = 0; |
740 | break; | 908 | break; |
741 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: | 909 | case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU: |