diff options
author | Mark A. Greer <mgreer@animalcreek.com> | 2014-09-23 19:38:13 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-11-28 06:39:55 -0500 |
commit | 384ab1d174a11292af63674a26eaa99864db9b48 (patch) | |
tree | 92330bc261e79bc6788543930e590f0fed706b63 /net | |
parent | 49dbb14e30c3249f98fe243c3e21b91d10c5c59b (diff) |
NFC: digital: Add NFC-DEP Initiator-side ATN Support
When an NFC-DEP Initiator times out when waiting for
a DEP_RES from the Target, its supposed to send an
ATN to the Target. The Target should respond to the
ATN with a similar ATN PDU and the Initiator can then
resend the last non-ATN PDU that it sent. No more
than 'N(retry,atn)' are to be send where
2 <= 'N(retry,atn)' <= 5. If the Initiator had just
sent a NACK PDU when the timeout occurred, it is to
continue sending NACKs until 'N(retry,nack)' NACKs
have been send. This is described in section
14.12.5.6 of the NFC-DEP Digital Protocol Spec.
The digital layer's NFC-DEP code doesn't implement
this so add that support.
The value chosen for 'N(retry,atn)' is 2.
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/nfc/digital_dep.c | 104 |
1 files changed, 98 insertions, 6 deletions
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index 31418edbe78e..8f1fefd2ed14 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "digital.h" | 18 | #include "digital.h" |
19 | 19 | ||
20 | #define DIGITAL_NFC_DEP_N_RETRY_NACK 2 | 20 | #define DIGITAL_NFC_DEP_N_RETRY_NACK 2 |
21 | #define DIGITAL_NFC_DEP_N_RETRY_ATN 2 | ||
21 | 22 | ||
22 | #define DIGITAL_NFC_DEP_FRAME_DIR_OUT 0xD4 | 23 | #define DIGITAL_NFC_DEP_FRAME_DIR_OUT 0xD4 |
23 | #define DIGITAL_NFC_DEP_FRAME_DIR_IN 0xD5 | 24 | #define DIGITAL_NFC_DEP_FRAME_DIR_IN 0xD5 |
@@ -523,10 +524,16 @@ static int digital_in_send_ack(struct nfc_digital_dev *ddev, | |||
523 | 524 | ||
524 | ddev->skb_add_crc(skb); | 525 | ddev->skb_add_crc(skb); |
525 | 526 | ||
527 | ddev->saved_skb = skb_get(skb); | ||
528 | ddev->saved_skb_len = skb->len; | ||
529 | |||
526 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | 530 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, |
527 | data_exch); | 531 | data_exch); |
528 | if (rc) | 532 | if (rc) { |
529 | kfree_skb(skb); | 533 | kfree_skb(skb); |
534 | kfree_skb(ddev->saved_skb); | ||
535 | ddev->saved_skb = NULL; | ||
536 | } | ||
530 | 537 | ||
531 | return rc; | 538 | return rc; |
532 | } | 539 | } |
@@ -563,6 +570,37 @@ static int digital_in_send_nack(struct nfc_digital_dev *ddev, | |||
563 | return rc; | 570 | return rc; |
564 | } | 571 | } |
565 | 572 | ||
573 | static int digital_in_send_atn(struct nfc_digital_dev *ddev, | ||
574 | struct digital_data_exch *data_exch) | ||
575 | { | ||
576 | struct digital_dep_req_res *dep_req; | ||
577 | struct sk_buff *skb; | ||
578 | int rc; | ||
579 | |||
580 | skb = digital_skb_alloc(ddev, 1); | ||
581 | if (!skb) | ||
582 | return -ENOMEM; | ||
583 | |||
584 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
585 | |||
586 | dep_req = (struct digital_dep_req_res *)skb->data; | ||
587 | |||
588 | dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; | ||
589 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; | ||
590 | dep_req->pfb = DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU; | ||
591 | |||
592 | digital_skb_push_dep_sod(ddev, skb); | ||
593 | |||
594 | ddev->skb_add_crc(skb); | ||
595 | |||
596 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | ||
597 | data_exch); | ||
598 | if (rc) | ||
599 | kfree_skb(skb); | ||
600 | |||
601 | return rc; | ||
602 | } | ||
603 | |||
566 | static int digital_in_send_rtox(struct nfc_digital_dev *ddev, | 604 | static int digital_in_send_rtox(struct nfc_digital_dev *ddev, |
567 | struct digital_data_exch *data_exch, u8 rtox) | 605 | struct digital_data_exch *data_exch, u8 rtox) |
568 | { | 606 | { |
@@ -589,14 +627,30 @@ static int digital_in_send_rtox(struct nfc_digital_dev *ddev, | |||
589 | 627 | ||
590 | ddev->skb_add_crc(skb); | 628 | ddev->skb_add_crc(skb); |
591 | 629 | ||
630 | ddev->saved_skb = skb_get(skb); | ||
631 | ddev->saved_skb_len = skb->len; | ||
632 | |||
592 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | 633 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, |
593 | data_exch); | 634 | data_exch); |
594 | if (rc) | 635 | if (rc) { |
595 | kfree_skb(skb); | 636 | kfree_skb(skb); |
637 | kfree_skb(ddev->saved_skb); | ||
638 | ddev->saved_skb = NULL; | ||
639 | } | ||
596 | 640 | ||
597 | return rc; | 641 | return rc; |
598 | } | 642 | } |
599 | 643 | ||
644 | static int digital_in_send_saved_skb(struct nfc_digital_dev *ddev, | ||
645 | struct digital_data_exch *data_exch) | ||
646 | { | ||
647 | skb_get(ddev->saved_skb); | ||
648 | skb_push(ddev->saved_skb, ddev->saved_skb_len); | ||
649 | |||
650 | return digital_in_send_cmd(ddev, ddev->saved_skb, 1500, | ||
651 | digital_in_recv_dep_res, data_exch); | ||
652 | } | ||
653 | |||
600 | static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | 654 | static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, |
601 | struct sk_buff *resp) | 655 | struct sk_buff *resp) |
602 | { | 656 | { |
@@ -610,13 +664,24 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
610 | rc = PTR_ERR(resp); | 664 | rc = PTR_ERR(resp); |
611 | resp = NULL; | 665 | resp = NULL; |
612 | 666 | ||
613 | if ((rc != -ETIMEDOUT) && | 667 | if (((rc != -ETIMEDOUT) || ddev->nack_count) && |
614 | (ddev->nack_count++ < DIGITAL_NFC_DEP_N_RETRY_NACK)) { | 668 | (ddev->nack_count++ < DIGITAL_NFC_DEP_N_RETRY_NACK)) { |
669 | ddev->atn_count = 0; | ||
670 | |||
615 | rc = digital_in_send_nack(ddev, data_exch); | 671 | rc = digital_in_send_nack(ddev, data_exch); |
616 | if (rc) | 672 | if (rc) |
617 | goto error; | 673 | goto error; |
618 | 674 | ||
619 | return; | 675 | return; |
676 | } else if ((rc == -ETIMEDOUT) && | ||
677 | (ddev->atn_count++ < DIGITAL_NFC_DEP_N_RETRY_ATN)) { | ||
678 | ddev->nack_count = 0; | ||
679 | |||
680 | rc = digital_in_send_atn(ddev, data_exch); | ||
681 | if (rc) | ||
682 | goto error; | ||
683 | |||
684 | return; | ||
620 | } | 685 | } |
621 | 686 | ||
622 | goto exit; | 687 | goto exit; |
@@ -632,6 +697,8 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
632 | if (rc) { | 697 | if (rc) { |
633 | if ((resp->len >= 4) && | 698 | if ((resp->len >= 4) && |
634 | (ddev->nack_count++ < DIGITAL_NFC_DEP_N_RETRY_NACK)) { | 699 | (ddev->nack_count++ < DIGITAL_NFC_DEP_N_RETRY_NACK)) { |
700 | ddev->atn_count = 0; | ||
701 | |||
635 | rc = digital_in_send_nack(ddev, data_exch); | 702 | rc = digital_in_send_nack(ddev, data_exch); |
636 | if (rc) | 703 | if (rc) |
637 | goto error; | 704 | goto error; |
@@ -645,6 +712,7 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
645 | goto error; | 712 | goto error; |
646 | } | 713 | } |
647 | 714 | ||
715 | ddev->atn_count = 0; | ||
648 | ddev->nack_count = 0; | 716 | ddev->nack_count = 0; |
649 | 717 | ||
650 | if (resp->len > ddev->local_payload_max) { | 718 | if (resp->len > ddev->local_payload_max) { |
@@ -692,6 +760,9 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
692 | ddev->curr_nfc_dep_pni = | 760 | ddev->curr_nfc_dep_pni = |
693 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); | 761 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); |
694 | 762 | ||
763 | kfree_skb(ddev->saved_skb); | ||
764 | ddev->saved_skb = NULL; | ||
765 | |||
695 | resp = digital_recv_dep_data_gather(ddev, pfb, resp, | 766 | resp = digital_recv_dep_data_gather(ddev, pfb, resp, |
696 | digital_in_send_ack, | 767 | digital_in_send_ack, |
697 | data_exch); | 768 | data_exch); |
@@ -722,6 +793,9 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
722 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); | 793 | DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1); |
723 | 794 | ||
724 | if (ddev->chaining_skb && !DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { | 795 | if (ddev->chaining_skb && !DIGITAL_NFC_DEP_NACK_BIT_SET(pfb)) { |
796 | kfree_skb(ddev->saved_skb); | ||
797 | ddev->saved_skb = NULL; | ||
798 | |||
725 | rc = digital_in_send_dep_req(ddev, NULL, | 799 | rc = digital_in_send_dep_req(ddev, NULL, |
726 | ddev->chaining_skb, | 800 | ddev->chaining_skb, |
727 | ddev->data_exch); | 801 | ddev->data_exch); |
@@ -736,11 +810,19 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
736 | goto exit; | 810 | goto exit; |
737 | 811 | ||
738 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: | 812 | case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU: |
739 | if (!DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { | 813 | if (!DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) { /* ATN */ |
740 | rc = -EINVAL; | 814 | rc = digital_in_send_saved_skb(ddev, data_exch); |
741 | goto error; | 815 | if (rc) { |
816 | kfree_skb(ddev->saved_skb); | ||
817 | goto error; | ||
818 | } | ||
819 | |||
820 | return; | ||
742 | } | 821 | } |
743 | 822 | ||
823 | kfree_skb(ddev->saved_skb); | ||
824 | ddev->saved_skb = NULL; | ||
825 | |||
744 | rc = digital_in_send_rtox(ddev, data_exch, resp->data[0]); | 826 | rc = digital_in_send_rtox(ddev, data_exch, resp->data[0]); |
745 | if (rc) | 827 | if (rc) |
746 | goto error; | 828 | goto error; |
@@ -758,6 +840,9 @@ error: | |||
758 | kfree_skb(ddev->chaining_skb); | 840 | kfree_skb(ddev->chaining_skb); |
759 | ddev->chaining_skb = NULL; | 841 | ddev->chaining_skb = NULL; |
760 | 842 | ||
843 | kfree_skb(ddev->saved_skb); | ||
844 | ddev->saved_skb = NULL; | ||
845 | |||
761 | if (rc) | 846 | if (rc) |
762 | kfree_skb(resp); | 847 | kfree_skb(resp); |
763 | } | 848 | } |
@@ -778,6 +863,7 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev, | |||
778 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; | 863 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; |
779 | dep_req->pfb = ddev->curr_nfc_dep_pni; | 864 | dep_req->pfb = ddev->curr_nfc_dep_pni; |
780 | 865 | ||
866 | ddev->atn_count = 0; | ||
781 | ddev->nack_count = 0; | 867 | ddev->nack_count = 0; |
782 | 868 | ||
783 | chaining_skb = ddev->chaining_skb; | 869 | chaining_skb = ddev->chaining_skb; |
@@ -790,6 +876,9 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev, | |||
790 | 876 | ||
791 | ddev->skb_add_crc(tmp_skb); | 877 | ddev->skb_add_crc(tmp_skb); |
792 | 878 | ||
879 | ddev->saved_skb = skb_get(tmp_skb); | ||
880 | ddev->saved_skb_len = tmp_skb->len; | ||
881 | |||
793 | rc = digital_in_send_cmd(ddev, tmp_skb, 1500, digital_in_recv_dep_res, | 882 | rc = digital_in_send_cmd(ddev, tmp_skb, 1500, digital_in_recv_dep_res, |
794 | data_exch); | 883 | data_exch); |
795 | if (rc) { | 884 | if (rc) { |
@@ -798,6 +887,9 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev, | |||
798 | 887 | ||
799 | kfree_skb(chaining_skb); | 888 | kfree_skb(chaining_skb); |
800 | ddev->chaining_skb = NULL; | 889 | ddev->chaining_skb = NULL; |
890 | |||
891 | kfree_skb(ddev->saved_skb); | ||
892 | ddev->saved_skb = NULL; | ||
801 | } | 893 | } |
802 | 894 | ||
803 | return rc; | 895 | return rc; |