Skip to content

Commit 4aeee68

Browse files
cricard13Samuel Ortiz
authored andcommitted
NFC: nci: Add dynamic logical connections support
The current NCI core only support the RF static connection. For other NFC features such as Secure Element communication, we may need to create logical connections to the NFCEE (Execution Environment. In order to track each logical connection ID dynamically, we add a linked list of connection info pointers to the nci_dev structure. Signed-off-by: Christophe Ricard <[email protected]> Signed-off-by: Samuel Ortiz <[email protected]>
1 parent 86b3bfe commit 4aeee68

File tree

5 files changed

+152
-40
lines changed

5 files changed

+152
-40
lines changed

include/net/nfc/nci_core.h

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,23 @@ struct nci_ops {
8282

8383
#define NCI_MAX_SUPPORTED_RF_INTERFACES 4
8484
#define NCI_MAX_DISCOVERED_TARGETS 10
85+
#define NCI_MAX_NUM_NFCEE 255
86+
#define NCI_MAX_CONN_ID 7
87+
88+
struct nci_conn_info {
89+
struct list_head list;
90+
__u8 id; /* can be an RF Discovery ID or an NFCEE ID */
91+
__u8 conn_id;
92+
__u8 max_pkt_payload_len;
93+
94+
atomic_t credits_cnt;
95+
__u8 initial_num_credits;
96+
97+
data_exchange_cb_t data_exchange_cb;
98+
void *data_exchange_cb_context;
99+
100+
struct sk_buff *rx_skb;
101+
};
85102

86103
/* NCI Core structures */
87104
struct nci_dev {
@@ -95,7 +112,9 @@ struct nci_dev {
95112
unsigned long flags;
96113

97114
atomic_t cmd_cnt;
98-
atomic_t credits_cnt;
115+
__u8 cur_conn_id;
116+
117+
struct list_head conn_info_list;
99118

100119
struct timer_list cmd_timer;
101120
struct timer_list data_timer;
@@ -141,13 +160,10 @@ struct nci_dev {
141160
__u8 manufact_id;
142161
__u32 manufact_specific_info;
143162

144-
/* received during NCI_OP_RF_INTF_ACTIVATED_NTF */
145-
__u8 max_data_pkt_payload_size;
146-
__u8 initial_num_credits;
163+
/* Save RF Discovery ID or NFCEE ID under conn_create */
164+
__u8 cur_id;
147165

148166
/* stored during nci_data_exchange */
149-
data_exchange_cb_t data_exchange_cb;
150-
void *data_exchange_cb_context;
151167
struct sk_buff *rx_data_reassembly;
152168

153169
/* stored during intf_activated_ntf */
@@ -200,7 +216,7 @@ void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb);
200216
int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload);
201217
int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb);
202218
void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
203-
int err);
219+
__u8 conn_id, int err);
204220
void nci_clear_target_list(struct nci_dev *ndev);
205221

206222
/* ----- NCI requests ----- */
@@ -209,6 +225,8 @@ void nci_clear_target_list(struct nci_dev *ndev);
209225
#define NCI_REQ_CANCELED 2
210226

211227
void nci_req_complete(struct nci_dev *ndev, int result);
228+
struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev,
229+
int conn_id);
212230

213231
/* ----- NCI status code ----- */
214232
int nci_to_errno(__u8 code);

net/nfc/nci/core.c

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ static void nci_cmd_work(struct work_struct *work);
4545
static void nci_rx_work(struct work_struct *work);
4646
static void nci_tx_work(struct work_struct *work);
4747

48+
struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev,
49+
int conn_id)
50+
{
51+
struct nci_conn_info *conn_info;
52+
53+
list_for_each_entry(conn_info, &ndev->conn_info_list, list) {
54+
if (conn_info->conn_id == conn_id)
55+
return conn_info;
56+
}
57+
58+
return NULL;
59+
}
60+
4861
/* ---- NCI requests ---- */
4962

5063
void nci_req_complete(struct nci_dev *ndev, int result)
@@ -712,6 +725,11 @@ static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
712725
{
713726
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
714727
int rc;
728+
struct nci_conn_info *conn_info;
729+
730+
conn_info = nci_get_conn_info_by_conn_id(ndev, NCI_STATIC_RF_CONN_ID);
731+
if (!conn_info)
732+
return -EPROTO;
715733

716734
pr_debug("target_idx %d, len %d\n", target->idx, skb->len);
717735

@@ -724,8 +742,8 @@ static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
724742
return -EBUSY;
725743

726744
/* store cb and context to be used on receiving data */
727-
ndev->data_exchange_cb = cb;
728-
ndev->data_exchange_cb_context = cb_context;
745+
conn_info->data_exchange_cb = cb;
746+
conn_info->data_exchange_cb_context = cb_context;
729747

730748
rc = nci_send_data(ndev, NCI_STATIC_RF_CONN_ID, skb);
731749
if (rc)
@@ -913,6 +931,7 @@ int nci_register_device(struct nci_dev *ndev)
913931
(unsigned long) ndev);
914932

915933
mutex_init(&ndev->req_lock);
934+
INIT_LIST_HEAD(&ndev->conn_info_list);
916935

917936
rc = nfc_register_device(ndev->nfc_dev);
918937
if (rc)
@@ -938,12 +957,19 @@ EXPORT_SYMBOL(nci_register_device);
938957
*/
939958
void nci_unregister_device(struct nci_dev *ndev)
940959
{
960+
struct nci_conn_info *conn_info, *n;
961+
941962
nci_close_device(ndev);
942963

943964
destroy_workqueue(ndev->cmd_wq);
944965
destroy_workqueue(ndev->rx_wq);
945966
destroy_workqueue(ndev->tx_wq);
946967

968+
list_for_each_entry_safe(conn_info, n, &ndev->conn_info_list, list) {
969+
list_del(&conn_info->list);
970+
/* conn_info is allocated with devm_kzalloc */
971+
}
972+
947973
nfc_unregister_device(ndev->nfc_dev);
948974
}
949975
EXPORT_SYMBOL(nci_unregister_device);
@@ -1027,20 +1053,25 @@ int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload)
10271053
static void nci_tx_work(struct work_struct *work)
10281054
{
10291055
struct nci_dev *ndev = container_of(work, struct nci_dev, tx_work);
1056+
struct nci_conn_info *conn_info;
10301057
struct sk_buff *skb;
10311058

1032-
pr_debug("credits_cnt %d\n", atomic_read(&ndev->credits_cnt));
1059+
conn_info = nci_get_conn_info_by_conn_id(ndev, ndev->cur_conn_id);
1060+
if (!conn_info)
1061+
return;
1062+
1063+
pr_debug("credits_cnt %d\n", atomic_read(&conn_info->credits_cnt));
10331064

10341065
/* Send queued tx data */
1035-
while (atomic_read(&ndev->credits_cnt)) {
1066+
while (atomic_read(&conn_info->credits_cnt)) {
10361067
skb = skb_dequeue(&ndev->tx_q);
10371068
if (!skb)
10381069
return;
10391070

10401071
/* Check if data flow control is used */
1041-
if (atomic_read(&ndev->credits_cnt) !=
1072+
if (atomic_read(&conn_info->credits_cnt) !=
10421073
NCI_DATA_FLOW_CONTROL_NOT_USED)
1043-
atomic_dec(&ndev->credits_cnt);
1074+
atomic_dec(&conn_info->credits_cnt);
10441075

10451076
pr_debug("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d\n",
10461077
nci_pbf(skb->data),
@@ -1092,7 +1123,9 @@ static void nci_rx_work(struct work_struct *work)
10921123
if (test_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags)) {
10931124
/* complete the data exchange transaction, if exists */
10941125
if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
1095-
nci_data_exchange_complete(ndev, NULL, -ETIMEDOUT);
1126+
nci_data_exchange_complete(ndev, NULL,
1127+
ndev->cur_conn_id,
1128+
-ETIMEDOUT);
10961129

10971130
clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
10981131
}

net/nfc/nci/data.c

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,20 @@
3636

3737
/* Complete data exchange transaction and forward skb to nfc core */
3838
void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
39-
int err)
39+
__u8 conn_id, int err)
4040
{
41-
data_exchange_cb_t cb = ndev->data_exchange_cb;
42-
void *cb_context = ndev->data_exchange_cb_context;
41+
struct nci_conn_info *conn_info;
42+
data_exchange_cb_t cb;
43+
void *cb_context;
44+
45+
conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
46+
if (!conn_info) {
47+
kfree_skb(skb);
48+
goto exit;
49+
}
50+
51+
cb = conn_info->data_exchange_cb;
52+
cb_context = conn_info->data_exchange_cb_context;
4353

4454
pr_debug("len %d, err %d\n", skb ? skb->len : 0, err);
4555

@@ -48,9 +58,6 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
4858
clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
4959

5060
if (cb) {
51-
ndev->data_exchange_cb = NULL;
52-
ndev->data_exchange_cb_context = NULL;
53-
5461
/* forward skb to nfc core */
5562
cb(cb_context, skb, err);
5663
} else if (skb) {
@@ -60,6 +67,7 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
6067
kfree_skb(skb);
6168
}
6269

70+
exit:
6371
clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
6472
}
6573

@@ -85,6 +93,7 @@ static inline void nci_push_data_hdr(struct nci_dev *ndev,
8593
static int nci_queue_tx_data_frags(struct nci_dev *ndev,
8694
__u8 conn_id,
8795
struct sk_buff *skb) {
96+
struct nci_conn_info *conn_info;
8897
int total_len = skb->len;
8998
unsigned char *data = skb->data;
9099
unsigned long flags;
@@ -95,11 +104,17 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
95104

96105
pr_debug("conn_id 0x%x, total_len %d\n", conn_id, total_len);
97106

107+
conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
108+
if (!conn_info) {
109+
rc = -EPROTO;
110+
goto free_exit;
111+
}
112+
98113
__skb_queue_head_init(&frags_q);
99114

100115
while (total_len) {
101116
frag_len =
102-
min_t(int, total_len, ndev->max_data_pkt_payload_size);
117+
min_t(int, total_len, conn_info->max_pkt_payload_len);
103118

104119
skb_frag = nci_skb_alloc(ndev,
105120
(NCI_DATA_HDR_SIZE + frag_len),
@@ -151,12 +166,19 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
151166
/* Send NCI data */
152167
int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
153168
{
169+
struct nci_conn_info *conn_info;
154170
int rc = 0;
155171

156172
pr_debug("conn_id 0x%x, plen %d\n", conn_id, skb->len);
157173

174+
conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
175+
if (!conn_info) {
176+
rc = -EPROTO;
177+
goto free_exit;
178+
}
179+
158180
/* check if the packet need to be fragmented */
159-
if (skb->len <= ndev->max_data_pkt_payload_size) {
181+
if (skb->len <= conn_info->max_pkt_payload_len) {
160182
/* no need to fragment packet */
161183
nci_push_data_hdr(ndev, conn_id, skb, NCI_PBF_LAST);
162184

@@ -170,6 +192,7 @@ int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
170192
}
171193
}
172194

195+
ndev->cur_conn_id = conn_id;
173196
queue_work(ndev->tx_wq, &ndev->tx_work);
174197

175198
goto exit;
@@ -185,7 +208,7 @@ int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
185208

186209
static void nci_add_rx_data_frag(struct nci_dev *ndev,
187210
struct sk_buff *skb,
188-
__u8 pbf, __u8 status)
211+
__u8 pbf, __u8 conn_id, __u8 status)
189212
{
190213
int reassembly_len;
191214
int err = 0;
@@ -229,16 +252,13 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev,
229252
}
230253

231254
exit:
232-
if (ndev->nfc_dev->rf_mode == NFC_RF_INITIATOR) {
233-
nci_data_exchange_complete(ndev, skb, err);
234-
} else if (ndev->nfc_dev->rf_mode == NFC_RF_TARGET) {
255+
if (ndev->nfc_dev->rf_mode == NFC_RF_TARGET) {
235256
/* Data received in Target mode, forward to nfc core */
236257
err = nfc_tm_data_received(ndev->nfc_dev, skb);
237258
if (err)
238259
pr_err("unable to handle received data\n");
239260
} else {
240-
pr_err("rf mode unknown\n");
241-
kfree_skb(skb);
261+
nci_data_exchange_complete(ndev, skb, conn_id, err);
242262
}
243263
}
244264

@@ -247,6 +267,8 @@ void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb)
247267
{
248268
__u8 pbf = nci_pbf(skb->data);
249269
__u8 status = 0;
270+
__u8 conn_id = nci_conn_id(skb->data);
271+
struct nci_conn_info *conn_info;
250272

251273
pr_debug("len %d\n", skb->len);
252274

@@ -255,6 +277,10 @@ void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb)
255277
nci_conn_id(skb->data),
256278
nci_plen(skb->data));
257279

280+
conn_info = nci_get_conn_info_by_conn_id(ndev, nci_conn_id(skb->data));
281+
if (!conn_info)
282+
return;
283+
258284
/* strip the nci data header */
259285
skb_pull(skb, NCI_DATA_HDR_SIZE);
260286

@@ -268,5 +294,5 @@ void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb)
268294
skb_trim(skb, (skb->len - 1));
269295
}
270296

271-
nci_add_rx_data_frag(ndev, skb, pbf, nci_to_errno(status));
297+
nci_add_rx_data_frag(ndev, skb, pbf, conn_id, nci_to_errno(status));
272298
}

0 commit comments

Comments
 (0)