aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark A. Greer <mgreer@animalcreek.com>2014-09-23 19:38:10 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2014-11-28 06:39:21 -0500
commitc12715ab3f0122971f75731b9c2f5b35836165cb (patch)
tree697dfc8815cefd45c1c5f992928c768560015e5d
parent3bd2a5bcc6cd7b8d588aa9ffa947177721eba18e (diff)
NFC: digital: Add NFC-DEP Receive Chaining Support
When the peer in an NFC-DEP exchange has a packet to send that is larger than the local maximum payload, it sets the 'MI' bit in the 'I' PDU. This indicates that NFC-DEP chaining is to occur. When such a PDU is received, the local side responds with an 'ACK' PDU and this continues until the peer sends an 'I' PDU with the 'MI' bit cleared. This indicates that the chaining sequence is complete and the entire packet has been transferred. Receiving chained PDUs is currently not supported by the digital layer so add that support. When a chaining sequence is initiated by the peer, the digital layer will allocate an skb large enough to hold 8 maximum sized frame payloads. The maximum payload can range from 64 to 254 bytes so 8 * 254 = 2032 seems like a reasonable compromise between potentially wasting memory and constantly reallocating new, larger skbs. 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.c180
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
110static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, 110static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg,
111 struct sk_buff *resp); 111 struct sk_buff *resp);
112static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
113 struct sk_buff *resp);
112 114
113static const u8 digital_payload_bits_map[4] = { 115static 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
206static struct sk_buff *
207digital_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
263error:
264 kfree_skb(resp);
265
266 kfree_skb(ddev->chaining_skb);
267 ddev->chaining_skb = NULL;
268
269 return ERR_PTR(rc);
270}
271
204static void digital_in_recv_psl_res(struct nfc_digital_dev *ddev, void *arg, 272static 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
500static 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
432static int digital_in_send_rtox(struct nfc_digital_dev *ddev, 532static 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
584exit: 695exit:
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
774static 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
663static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg, 816static 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: