diff options
author | Thierry Escande <thierry.escande@linux.intel.com> | 2014-01-26 18:31:32 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-02-16 17:49:54 -0500 |
commit | c813007f9ffb0b6e9f3dc43bfd9e28806aa57e5d (patch) | |
tree | 1a030aa83175313551eecfd7f23d08797481837b /net | |
parent | 12e3d241e42956da168fd499347855af799f62fb (diff) |
NFC: digital: Add ISO-DEP support for data exchange
When a type 4A target is activated, this change adds the ISO-DEP SoD
when sending frames and removes it when receiving responses. Chaining
is not supported so sent frames are rejected if they exceed remote FSC
bytes.
Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/nfc/digital.h | 5 | ||||
-rw-r--r-- | net/nfc/digital_core.c | 25 | ||||
-rw-r--r-- | net/nfc/digital_technology.c | 57 |
3 files changed, 83 insertions, 4 deletions
diff --git a/net/nfc/digital.h b/net/nfc/digital.h index 3c757dc7d44f..3759add68b1b 100644 --- a/net/nfc/digital.h +++ b/net/nfc/digital.h | |||
@@ -74,6 +74,11 @@ int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech); | |||
74 | int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech); | 74 | int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech); |
75 | int digital_in_send_iso15693_inv_req(struct nfc_digital_dev *ddev, u8 rf_tech); | 75 | int digital_in_send_iso15693_inv_req(struct nfc_digital_dev *ddev, u8 rf_tech); |
76 | 76 | ||
77 | int digital_in_iso_dep_pull_sod(struct nfc_digital_dev *ddev, | ||
78 | struct sk_buff *skb); | ||
79 | int digital_in_iso_dep_push_sod(struct nfc_digital_dev *ddev, | ||
80 | struct sk_buff *skb); | ||
81 | |||
77 | int digital_target_found(struct nfc_digital_dev *ddev, | 82 | int digital_target_found(struct nfc_digital_dev *ddev, |
78 | struct nfc_target *target, u8 protocol); | 83 | struct nfc_target *target, u8 protocol); |
79 | 84 | ||
diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index e1f240266adf..5b440e7d9598 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c | |||
@@ -624,20 +624,30 @@ static void digital_in_send_complete(struct nfc_digital_dev *ddev, void *arg, | |||
624 | 624 | ||
625 | if (IS_ERR(resp)) { | 625 | if (IS_ERR(resp)) { |
626 | rc = PTR_ERR(resp); | 626 | rc = PTR_ERR(resp); |
627 | resp = NULL; | ||
627 | goto done; | 628 | goto done; |
628 | } | 629 | } |
629 | 630 | ||
630 | if (ddev->curr_protocol == NFC_PROTO_MIFARE) | 631 | if (ddev->curr_protocol == NFC_PROTO_MIFARE) { |
631 | rc = digital_in_recv_mifare_res(resp); | 632 | rc = digital_in_recv_mifare_res(resp); |
632 | else | 633 | /* crc check is done in digital_in_recv_mifare_res() */ |
633 | rc = ddev->skb_check_crc(resp); | 634 | goto done; |
635 | } | ||
636 | |||
637 | if (ddev->curr_protocol == NFC_PROTO_ISO14443) { | ||
638 | rc = digital_in_iso_dep_pull_sod(ddev, resp); | ||
639 | if (rc) | ||
640 | goto done; | ||
641 | } | ||
642 | |||
643 | rc = ddev->skb_check_crc(resp); | ||
634 | 644 | ||
645 | done: | ||
635 | if (rc) { | 646 | if (rc) { |
636 | kfree_skb(resp); | 647 | kfree_skb(resp); |
637 | resp = NULL; | 648 | resp = NULL; |
638 | } | 649 | } |
639 | 650 | ||
640 | done: | ||
641 | data_exch->cb(data_exch->cb_context, resp, rc); | 651 | data_exch->cb(data_exch->cb_context, resp, rc); |
642 | 652 | ||
643 | kfree(data_exch); | 653 | kfree(data_exch); |
@@ -649,6 +659,7 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target, | |||
649 | { | 659 | { |
650 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); | 660 | struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); |
651 | struct digital_data_exch *data_exch; | 661 | struct digital_data_exch *data_exch; |
662 | int rc; | ||
652 | 663 | ||
653 | data_exch = kzalloc(sizeof(struct digital_data_exch), GFP_KERNEL); | 664 | data_exch = kzalloc(sizeof(struct digital_data_exch), GFP_KERNEL); |
654 | if (!data_exch) { | 665 | if (!data_exch) { |
@@ -662,6 +673,12 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target, | |||
662 | if (ddev->curr_protocol == NFC_PROTO_NFC_DEP) | 673 | if (ddev->curr_protocol == NFC_PROTO_NFC_DEP) |
663 | return digital_in_send_dep_req(ddev, target, skb, data_exch); | 674 | return digital_in_send_dep_req(ddev, target, skb, data_exch); |
664 | 675 | ||
676 | if (ddev->curr_protocol == NFC_PROTO_ISO14443) { | ||
677 | rc = digital_in_iso_dep_push_sod(ddev, skb); | ||
678 | if (rc) | ||
679 | return rc; | ||
680 | } | ||
681 | |||
665 | ddev->skb_add_crc(skb); | 682 | ddev->skb_add_crc(skb); |
666 | 683 | ||
667 | return digital_in_send_cmd(ddev, skb, 500, digital_in_send_complete, | 684 | return digital_in_send_cmd(ddev, skb, 500, digital_in_send_complete, |
diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c index 6649d9461dff..278c3fed27e0 100644 --- a/net/nfc/digital_technology.c +++ b/net/nfc/digital_technology.c | |||
@@ -61,6 +61,15 @@ | |||
61 | #define DIGITAL_ISO15693_RES_IS_VALID(flags) \ | 61 | #define DIGITAL_ISO15693_RES_IS_VALID(flags) \ |
62 | (!((flags) & DIGITAL_ISO15693_RES_FLAG_ERROR)) | 62 | (!((flags) & DIGITAL_ISO15693_RES_FLAG_ERROR)) |
63 | 63 | ||
64 | #define DIGITAL_ISO_DEP_I_PCB 0x02 | ||
65 | #define DIGITAL_ISO_DEP_PNI(pni) ((pni) & 0x01) | ||
66 | |||
67 | #define DIGITAL_ISO_DEP_PCB_TYPE(pcb) ((pcb) & 0xC0) | ||
68 | |||
69 | #define DIGITAL_ISO_DEP_I_BLOCK 0x00 | ||
70 | |||
71 | #define DIGITAL_ISO_DEP_BLOCK_HAS_DID(pcb) ((pcb) & 0x08) | ||
72 | |||
64 | static const u8 digital_ats_fsc[] = { | 73 | static const u8 digital_ats_fsc[] = { |
65 | 16, 24, 32, 40, 48, 64, 96, 128, | 74 | 16, 24, 32, 40, 48, 64, 96, 128, |
66 | }; | 75 | }; |
@@ -118,6 +127,54 @@ struct digital_iso15693_inv_res { | |||
118 | static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, | 127 | static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, |
119 | struct nfc_target *target); | 128 | struct nfc_target *target); |
120 | 129 | ||
130 | int digital_in_iso_dep_pull_sod(struct nfc_digital_dev *ddev, | ||
131 | struct sk_buff *skb) | ||
132 | { | ||
133 | u8 pcb; | ||
134 | u8 block_type; | ||
135 | |||
136 | if (skb->len < 1) | ||
137 | return -EIO; | ||
138 | |||
139 | pcb = *skb->data; | ||
140 | block_type = DIGITAL_ISO_DEP_PCB_TYPE(pcb); | ||
141 | |||
142 | /* No support fo R-block nor S-block */ | ||
143 | if (block_type != DIGITAL_ISO_DEP_I_BLOCK) { | ||
144 | pr_err("ISO_DEP R-block and S-block not supported\n"); | ||
145 | return -EIO; | ||
146 | } | ||
147 | |||
148 | if (DIGITAL_ISO_DEP_BLOCK_HAS_DID(pcb)) { | ||
149 | pr_err("DID field in ISO_DEP PCB not supported\n"); | ||
150 | return -EIO; | ||
151 | } | ||
152 | |||
153 | skb_pull(skb, 1); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | int digital_in_iso_dep_push_sod(struct nfc_digital_dev *ddev, | ||
159 | struct sk_buff *skb) | ||
160 | { | ||
161 | /* | ||
162 | * Chaining not supported so skb->len + 1 PCB byte + 2 CRC bytes must | ||
163 | * not be greater than remote FSC | ||
164 | */ | ||
165 | if (skb->len + 3 > ddev->target_fsc) | ||
166 | return -EIO; | ||
167 | |||
168 | skb_push(skb, 1); | ||
169 | |||
170 | *skb->data = DIGITAL_ISO_DEP_I_PCB | ddev->curr_nfc_dep_pni; | ||
171 | |||
172 | ddev->curr_nfc_dep_pni = | ||
173 | DIGITAL_ISO_DEP_PNI(ddev->curr_nfc_dep_pni + 1); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
121 | static void digital_in_recv_ats(struct nfc_digital_dev *ddev, void *arg, | 178 | static void digital_in_recv_ats(struct nfc_digital_dev *ddev, void *arg, |
122 | struct sk_buff *resp) | 179 | struct sk_buff *resp) |
123 | { | 180 | { |