aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorThierry Escande <thierry.escande@linux.intel.com>2014-01-26 18:31:32 -0500
committerSamuel Ortiz <sameo@linux.intel.com>2014-02-16 17:49:54 -0500
commitc813007f9ffb0b6e9f3dc43bfd9e28806aa57e5d (patch)
tree1a030aa83175313551eecfd7f23d08797481837b /net
parent12e3d241e42956da168fd499347855af799f62fb (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.h5
-rw-r--r--net/nfc/digital_core.c25
-rw-r--r--net/nfc/digital_technology.c57
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);
74int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech); 74int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech);
75int digital_in_send_iso15693_inv_req(struct nfc_digital_dev *ddev, u8 rf_tech); 75int digital_in_send_iso15693_inv_req(struct nfc_digital_dev *ddev, u8 rf_tech);
76 76
77int digital_in_iso_dep_pull_sod(struct nfc_digital_dev *ddev,
78 struct sk_buff *skb);
79int digital_in_iso_dep_push_sod(struct nfc_digital_dev *ddev,
80 struct sk_buff *skb);
81
77int digital_target_found(struct nfc_digital_dev *ddev, 82int 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
645done:
635 if (rc) { 646 if (rc) {
636 kfree_skb(resp); 647 kfree_skb(resp);
637 resp = NULL; 648 resp = NULL;
638 } 649 }
639 650
640done:
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
64static const u8 digital_ats_fsc[] = { 73static 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 {
118static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, 127static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev,
119 struct nfc_target *target); 128 struct nfc_target *target);
120 129
130int 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
158int 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
121static void digital_in_recv_ats(struct nfc_digital_dev *ddev, void *arg, 178static void digital_in_recv_ats(struct nfc_digital_dev *ddev, void *arg,
122 struct sk_buff *resp) 179 struct sk_buff *resp)
123{ 180{