diff options
author | Mark A. Greer <mgreer@animalcreek.com> | 2014-09-23 19:38:11 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-11-28 06:39:33 -0500 |
commit | a80509c76bf2b10dae76f3caea343ac4b85c72b4 (patch) | |
tree | 924f14ca602ddecd0bb5b81e7201628882b07375 /net/nfc/digital_dep.c | |
parent | c12715ab3f0122971f75731b9c2f5b35836165cb (diff) |
NFC: digital: Add NFC-DEP Initiator-side NACK Support
When an NFC-DEP Initiator receives a frame with
an incorrect CRC or with a parity error, and the
frame is at least 4 bytes long, its supposed to
send a NACK to the Target. The Initiator can
send up to 'N(retry,nack)' consecutive NACKs
where 2 <= 'N(retry,nack)' <= 5. When the limit
is exceeded, a PROTOCOL EXCEPTION is raised.
Any other type of transmission error is to be
ignored and the Initiator should continue
waiting for a new frame. This is described
in section 14.12.5.4 of the NFC Digital Protocol
Spec.
The digital layer's NFC-DEP code doesn't implement
any of this so add it. This support diverges from
the spec in two significant ways:
a) NACKs will be sent for ANY error reported by the
driver except a timeout. This is done because
there is currently no way for the digital layer
to distinguish a CRC or parity error from any
other type of error reported by the driver.
b) All other errors will cause a PROTOCOL EXCEPTION
even frames with CRC errors that are less than 4
bytes.
The value chosen for 'N(retry,nack)' is 2.
Targets do not send NACK PDUs.
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/nfc/digital_dep.c')
-rw-r--r-- | net/nfc/digital_dep.c | 69 |
1 files changed, 64 insertions, 5 deletions
diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c index 35a9edf0e360..9840e858ec5b 100644 --- a/net/nfc/digital_dep.c +++ b/net/nfc/digital_dep.c | |||
@@ -17,6 +17,8 @@ | |||
17 | 17 | ||
18 | #include "digital.h" | 18 | #include "digital.h" |
19 | 19 | ||
20 | #define DIGITAL_NFC_DEP_N_RETRY_NACK 2 | ||
21 | |||
20 | #define DIGITAL_NFC_DEP_FRAME_DIR_OUT 0xD4 | 22 | #define DIGITAL_NFC_DEP_FRAME_DIR_OUT 0xD4 |
21 | #define DIGITAL_NFC_DEP_FRAME_DIR_IN 0xD5 | 23 | #define DIGITAL_NFC_DEP_FRAME_DIR_IN 0xD5 |
22 | 24 | ||
@@ -529,6 +531,38 @@ static int digital_in_send_ack(struct nfc_digital_dev *ddev, | |||
529 | return rc; | 531 | return rc; |
530 | } | 532 | } |
531 | 533 | ||
534 | static int digital_in_send_nack(struct nfc_digital_dev *ddev, | ||
535 | struct digital_data_exch *data_exch) | ||
536 | { | ||
537 | struct digital_dep_req_res *dep_req; | ||
538 | struct sk_buff *skb; | ||
539 | int rc; | ||
540 | |||
541 | skb = digital_skb_alloc(ddev, 1); | ||
542 | if (!skb) | ||
543 | return -ENOMEM; | ||
544 | |||
545 | skb_push(skb, sizeof(struct digital_dep_req_res)); | ||
546 | |||
547 | dep_req = (struct digital_dep_req_res *)skb->data; | ||
548 | |||
549 | dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT; | ||
550 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; | ||
551 | dep_req->pfb = DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU | | ||
552 | DIGITAL_NFC_DEP_PFB_NACK_BIT | ddev->curr_nfc_dep_pni; | ||
553 | |||
554 | digital_skb_push_dep_sod(ddev, skb); | ||
555 | |||
556 | ddev->skb_add_crc(skb); | ||
557 | |||
558 | rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res, | ||
559 | data_exch); | ||
560 | if (rc) | ||
561 | kfree_skb(skb); | ||
562 | |||
563 | return rc; | ||
564 | } | ||
565 | |||
532 | static int digital_in_send_rtox(struct nfc_digital_dev *ddev, | 566 | static int digital_in_send_rtox(struct nfc_digital_dev *ddev, |
533 | struct digital_data_exch *data_exch, u8 rtox) | 567 | struct digital_data_exch *data_exch, u8 rtox) |
534 | { | 568 | { |
@@ -575,20 +609,43 @@ static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg, | |||
575 | if (IS_ERR(resp)) { | 609 | if (IS_ERR(resp)) { |
576 | rc = PTR_ERR(resp); | 610 | rc = PTR_ERR(resp); |
577 | resp = NULL; | 611 | resp = NULL; |
612 | |||
613 | if ((rc != -ETIMEDOUT) && | ||
614 | (ddev->nack_count++ < DIGITAL_NFC_DEP_N_RETRY_NACK)) { | ||
615 | rc = digital_in_send_nack(ddev, data_exch); | ||
616 | if (rc) | ||
617 | goto error; | ||
618 | |||
619 | return; | ||
620 | } | ||
621 | |||
622 | goto exit; | ||
623 | } | ||
624 | |||
625 | rc = digital_skb_pull_dep_sod(ddev, resp); | ||
626 | if (rc) { | ||
627 | PROTOCOL_ERR("14.4.1.2"); | ||
578 | goto exit; | 628 | goto exit; |
579 | } | 629 | } |
580 | 630 | ||
581 | rc = ddev->skb_check_crc(resp); | 631 | rc = ddev->skb_check_crc(resp); |
582 | if (rc) { | 632 | if (rc) { |
633 | if ((resp->len >= 4) && | ||
634 | (ddev->nack_count++ < DIGITAL_NFC_DEP_N_RETRY_NACK)) { | ||
635 | rc = digital_in_send_nack(ddev, data_exch); | ||
636 | if (rc) | ||
637 | goto error; | ||
638 | |||
639 | kfree_skb(resp); | ||
640 | |||
641 | return; | ||
642 | } | ||
643 | |||
583 | PROTOCOL_ERR("14.4.1.6"); | 644 | PROTOCOL_ERR("14.4.1.6"); |
584 | goto error; | 645 | goto error; |
585 | } | 646 | } |
586 | 647 | ||
587 | rc = digital_skb_pull_dep_sod(ddev, resp); | 648 | ddev->nack_count = 0; |
588 | if (rc) { | ||
589 | PROTOCOL_ERR("14.4.1.2"); | ||
590 | goto exit; | ||
591 | } | ||
592 | 649 | ||
593 | if (resp->len > ddev->local_payload_max) { | 650 | if (resp->len > ddev->local_payload_max) { |
594 | rc = -EMSGSIZE; | 651 | rc = -EMSGSIZE; |
@@ -721,6 +778,8 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev, | |||
721 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; | 778 | dep_req->cmd = DIGITAL_CMD_DEP_REQ; |
722 | dep_req->pfb = ddev->curr_nfc_dep_pni; | 779 | dep_req->pfb = ddev->curr_nfc_dep_pni; |
723 | 780 | ||
781 | ddev->nack_count = 0; | ||
782 | |||
724 | chaining_skb = ddev->chaining_skb; | 783 | chaining_skb = ddev->chaining_skb; |
725 | 784 | ||
726 | tmp_skb = digital_send_dep_data_prep(ddev, skb, dep_req, data_exch); | 785 | tmp_skb = digital_send_dep_data_prep(ddev, skb, dep_req, data_exch); |