From a9a741a7e2e6337ae5c030e78827c233c08902a7 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 30 Apr 2012 18:21:51 +0200 Subject: NFC: Prepare asynchronous error management for driver and shdlc Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/hci/core.c | 8 ++++++++ net/nfc/hci/shdlc.c | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index a8b0b71e8f86..1dc6485343b9 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -717,6 +717,14 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev) } EXPORT_SYMBOL(nfc_hci_get_clientdata); +void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) +{ + /* TODO: lower layer has permanent failure. + * complete potential HCI command or send an empty tag discovered event + */ +} +EXPORT_SYMBOL(nfc_hci_driver_failure); + void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) { struct hcp_packet *packet; diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 6b836e6242b7..d7c74d152a72 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c @@ -523,10 +523,6 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) r = shdlc->ops->xmit(shdlc, skb); if (r < 0) { - /* - * TODO: Cannot send, shdlc machine is dead, we - * must propagate the information up to HCI. - */ shdlc->hard_fault = r; break; } @@ -590,6 +586,11 @@ static void nfc_shdlc_sm_work(struct work_struct *work) skb_queue_purge(&shdlc->ack_pending_q); break; case SHDLC_CONNECTING: + if (shdlc->hard_fault) { + nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); + break; + } + if (shdlc->connect_tries++ < 5) r = nfc_shdlc_connect_initiate(shdlc); else @@ -610,6 +611,11 @@ static void nfc_shdlc_sm_work(struct work_struct *work) } nfc_shdlc_handle_rcv_queue(shdlc); + + if (shdlc->hard_fault) { + nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); + break; + } break; case SHDLC_CONNECTED: nfc_shdlc_handle_rcv_queue(shdlc); @@ -637,10 +643,7 @@ static void nfc_shdlc_sm_work(struct work_struct *work) } if (shdlc->hard_fault) { - /* - * TODO: Handle hard_fault that occured during - * this invocation of the shdlc worker - */ + nfc_hci_driver_failure(shdlc->hdev, shdlc->hard_fault); } break; default: -- cgit v1.2.3 From d3b404453192aa195ccfb2f0d946f880b16f8b1f Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Thu, 3 May 2012 14:53:20 +0200 Subject: NFC: Removed addressed shdlc TODOs The questions asked in the comments have been answered and addressed. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/hci/shdlc.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index d7c74d152a72..18d1536df5f6 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c @@ -340,15 +340,6 @@ static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) shdlc->state = SHDLC_CONNECTED; } else { shdlc->state = SHDLC_DISCONNECTED; - - /* - * TODO: Could it be possible that there are pending - * executing commands that are waiting for connect to complete - * before they can be carried? As connect is a blocking - * operation, it would require that the userspace process can - * send commands on the same device from a second thread before - * the device is up. I don't think that is possible, is it? - */ } shdlc->connect_result = r; @@ -926,8 +917,6 @@ void nfc_shdlc_free(struct nfc_shdlc *shdlc) { pr_debug("\n"); - /* TODO: Check that this cannot be called while still in use */ - nfc_hci_unregister_device(shdlc->hdev); nfc_hci_free_device(shdlc->hdev); -- cgit v1.2.3 From 5018e490c372d5ed0e0ced2f2471140bf5ba9b32 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Wed, 2 May 2012 11:23:11 +0200 Subject: NFC: Handle SHDLC RSET frames from an SHDLC connected chip shdlc reset may leave HCI in an inconsistent state by loosing parts of HCI frames. Handle this case by reporting an unrecoverable error to HCI. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/hci/shdlc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 18d1536df5f6..6f840c18c892 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c @@ -404,12 +404,12 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, r = nfc_shdlc_connect_send_ua(shdlc); nfc_shdlc_connect_complete(shdlc, r); } - } else if (shdlc->state > SHDLC_NEGOCIATING) { + } else if (shdlc->state == SHDLC_CONNECTED) { /* - * TODO: Chip wants to reset link - * send ua, empty skb lists, reset counters - * propagate info to HCI layer + * Chip wants to reset link. This is unexpected and + * unsupported. */ + shdlc->hard_fault = -ECONNRESET; } break; case U_FRAME_UA: -- cgit v1.2.3 From 1c215d79a18a22fc6c2a9ef8658d426bac492b58 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Wed, 2 May 2012 11:37:19 +0200 Subject: NFC: Remove an impossible HCI error case nfc_hci_recv_frame can not be called with a NULL skb. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/hci/core.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 1dc6485343b9..1a009d554fd7 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -735,16 +735,6 @@ void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) struct sk_buff *frag_skb; int msg_len; - if (skb == NULL) { - /* TODO ELa: lower layer had permanent failure, need to - * propagate that up - */ - - skb_queue_purge(&hdev->rx_hcp_frags); - - return; - } - packet = (struct hcp_packet *)skb->data; if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { skb_queue_tail(&hdev->rx_hcp_frags, skb); -- cgit v1.2.3 From 72b06f75fea45fa861f2e137bc94e56aab306c4b Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 11 Jun 2012 13:36:52 +0200 Subject: NFC: Implement HCP reaggregation allocation error case We can now report an ENOMEM error up to the HCI layer. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/hci/core.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 1a009d554fd7..7d4fdbc06a98 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -717,12 +717,18 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev) } EXPORT_SYMBOL(nfc_hci_get_clientdata); -void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) +static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) { - /* TODO: lower layer has permanent failure. + /* + * TODO: lower layer has permanent failure. * complete potential HCI command or send an empty tag discovered event */ } + +void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) +{ + nfc_hci_failure(hdev, err); +} EXPORT_SYMBOL(nfc_hci_driver_failure); void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) @@ -755,9 +761,8 @@ void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + msg_len, GFP_KERNEL); if (hcp_skb == NULL) { - /* TODO ELa: cannot deliver HCP message. How to - * propagate error up? - */ + nfc_hci_failure(hdev, -ENOMEM); + return; } *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; -- cgit v1.2.3 From 6c1c5b9e1d8a25268a607c762576b5c16e3e7230 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Thu, 3 May 2012 15:35:25 +0200 Subject: NFC: Changed HCI cmd execution completion result to std linux errno An HCI command can complete either from an HCI response (with an HCI result) or as a consequence of any other system error during processing. The completion therefore needs to take a standard errno code. The HCI response will convert its result to a standard errno before calling the completion. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/hci/command.c | 18 +++--------------- net/nfc/hci/core.c | 20 ++++++++++++++++---- net/nfc/hci/hci.h | 7 ++++--- 3 files changed, 23 insertions(+), 22 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 8729abf5f18b..12cd6f3f77ec 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c @@ -28,26 +28,14 @@ #include "hci.h" -static int nfc_hci_result_to_errno(u8 result) -{ - switch (result) { - case NFC_HCI_ANY_OK: - return 0; - case NFC_HCI_ANY_E_TIMEOUT: - return -ETIMEDOUT; - default: - return -1; - } -} - -static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, u8 result, +static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, int err, struct sk_buff *skb, void *cb_data) { struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)cb_data; - pr_debug("HCI Cmd completed with HCI result=%d\n", result); + pr_debug("HCI Cmd completed with result=%d\n", err); - hcp_ew->exec_result = nfc_hci_result_to_errno(result); + hcp_ew->exec_result = err; if (hcp_ew->exec_result == 0) hcp_ew->result_skb = skb; else diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 7d4fdbc06a98..5be7405ce6aa 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -32,6 +32,18 @@ /* Largest headroom needed for outgoing HCI commands */ #define HCI_CMDS_HEADROOM 1 +static int nfc_hci_result_to_errno(u8 result) +{ + switch (result) { + case NFC_HCI_ANY_OK: + return 0; + case NFC_HCI_ANY_E_TIMEOUT: + return -ETIME; + default: + return -1; + } +} + static void nfc_hci_msg_tx_work(struct work_struct *work) { struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev, @@ -46,7 +58,7 @@ static void nfc_hci_msg_tx_work(struct work_struct *work) if (timer_pending(&hdev->cmd_timer) == 0) { if (hdev->cmd_pending_msg->cb) hdev->cmd_pending_msg->cb(hdev, - NFC_HCI_ANY_E_TIMEOUT, + -ETIME, NULL, hdev-> cmd_pending_msg-> @@ -71,8 +83,7 @@ next_msg: kfree_skb(skb); skb_queue_purge(&msg->msg_frags); if (msg->cb) - msg->cb(hdev, NFC_HCI_ANY_E_NOK, NULL, - msg->cb_context); + msg->cb(hdev, r, NULL, msg->cb_context); kfree(msg); break; } @@ -129,7 +140,8 @@ void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, del_timer_sync(&hdev->cmd_timer); if (hdev->cmd_pending_msg->cb) - hdev->cmd_pending_msg->cb(hdev, result, skb, + hdev->cmd_pending_msg->cb(hdev, nfc_hci_result_to_errno(result), + skb, hdev->cmd_pending_msg->cb_context); else kfree_skb(skb); diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index 45f2fe4fd486..d3cde075ba60 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h @@ -37,10 +37,11 @@ struct hcp_packet { /* * HCI command execution completion callback. - * result will be one of the HCI response codes. - * skb contains the response data and must be disposed. + * result will be a standard linux error (may be converted from HCI response) + * skb contains the response data and must be disposed, or may be NULL if + * an error occured */ -typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, u8 result, +typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, int result, struct sk_buff *skb, void *cb_data); struct hcp_exec_waiter { -- cgit v1.2.3 From 456411ca812860d7ba06d3e4013ce1d8b9dbc7cd Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 11 Jun 2012 13:49:51 +0200 Subject: NFC: Driver failure API This API should be used by drivers, HCI, SHDLC or NCI stacks to report an unrecoverable error. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- include/net/nfc/nfc.h | 2 ++ net/nfc/core.c | 10 ++++++++++ 2 files changed, 12 insertions(+) (limited to 'net/nfc') diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 180964b954ab..6431f5e39022 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -204,4 +204,6 @@ int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode, int nfc_tm_deactivated(struct nfc_dev *dev); int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb); +void nfc_driver_failure(struct nfc_dev *dev, int err); + #endif /* __NET_NFC_H */ diff --git a/net/nfc/core.c b/net/nfc/core.c index 4177bb5104b9..32f28326b623 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -651,6 +651,16 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) } EXPORT_SYMBOL(nfc_target_lost); +void nfc_driver_failure(struct nfc_dev *dev, int err) +{ + /* + * TODO: if polling is active, send empty target_found + * or else do whatever makes sense to let user space + * know this device needs to be closed and reinitialized. + */ +} +EXPORT_SYMBOL(nfc_driver_failure); + static void nfc_release(struct device *d) { struct nfc_dev *dev = to_nfc_dev(d); -- cgit v1.2.3 From ccca0d6e8805f12fcda2e740c44afa7191923559 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Thu, 3 May 2012 15:59:37 +0200 Subject: NFC: Factorize HCI cmd completion HCI cmd can be completed either from an HCI response or from an internal driver or HCI error. This requires to factorize the completion code outside of the device lock. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/hci/core.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 5be7405ce6aa..9a1a12f8687e 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -127,21 +127,13 @@ static void nfc_hci_msg_rx_work(struct work_struct *work) } } -void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, - struct sk_buff *skb) +static void __nfc_hci_cmd_completion(struct nfc_hci_dev *hdev, int err, + struct sk_buff *skb) { - mutex_lock(&hdev->msg_tx_mutex); - - if (hdev->cmd_pending_msg == NULL) { - kfree_skb(skb); - goto exit; - } - del_timer_sync(&hdev->cmd_timer); if (hdev->cmd_pending_msg->cb) - hdev->cmd_pending_msg->cb(hdev, nfc_hci_result_to_errno(result), - skb, + hdev->cmd_pending_msg->cb(hdev, err, skb, hdev->cmd_pending_msg->cb_context); else kfree_skb(skb); @@ -150,6 +142,19 @@ void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, hdev->cmd_pending_msg = NULL; queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); +} + +void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, + struct sk_buff *skb) +{ + mutex_lock(&hdev->msg_tx_mutex); + + if (hdev->cmd_pending_msg == NULL) { + kfree_skb(skb); + goto exit; + } + + __nfc_hci_cmd_completion(hdev, nfc_hci_result_to_errno(result), skb); exit: mutex_unlock(&hdev->msg_tx_mutex); -- cgit v1.2.3 From a070c8591a503ec65e2c84ebaf3454e5cd76e3fe Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 11 Jun 2012 15:06:56 +0200 Subject: NFC: Implement HCI driver or internal error management If there is an ongoing HCI command executing, it will be completed, thereby pushing the error up to the core. Otherwise, HCI will directly notify the core with the error. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/hci/core.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 9a1a12f8687e..e6b2df3981b6 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -736,10 +736,17 @@ EXPORT_SYMBOL(nfc_hci_get_clientdata); static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) { - /* - * TODO: lower layer has permanent failure. - * complete potential HCI command or send an empty tag discovered event - */ + mutex_lock(&hdev->msg_tx_mutex); + + if (hdev->cmd_pending_msg == NULL) { + nfc_driver_failure(hdev->ndev, err); + goto exit; + } + + __nfc_hci_cmd_completion(hdev, err, NULL); + +exit: + mutex_unlock(&hdev->msg_tx_mutex); } void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) -- cgit v1.2.3 From 8668fdd6efb3a75e0d58a3287a47fa7e60a68a73 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Thu, 3 May 2012 16:21:58 +0200 Subject: NFC: Core must test the device polling state inside the device lock There can ever be only one call to nfc_targets_found() after polling has been engaged. This could be from a target discovered event from the driver, or from an error handler to notify poll will never complete. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/core.c b/net/nfc/core.c index 32f28326b623..94ccf07374a5 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -571,13 +571,18 @@ int nfc_targets_found(struct nfc_dev *dev, pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets); - dev->polling = false; - for (i = 0; i < n_targets; i++) targets[i].idx = dev->target_next_idx++; device_lock(&dev->dev); + if (dev->polling == false) { + device_unlock(&dev->dev); + return 0; + } + + dev->polling = false; + dev->targets_generation++; kfree(dev->targets); -- cgit v1.2.3 From d94f9c55ff22397cc3436840437da533e9263716 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Thu, 3 May 2012 16:33:32 +0200 Subject: NFC: nfc_targets_found() should accept zero target found The semantics for a zero target found event is that the polling operation could not complete. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/core.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/core.c b/net/nfc/core.c index 94ccf07374a5..749ee48d3600 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -560,6 +560,8 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); * The device driver must call this function when one or many nfc targets * are found. After calling this function, the device driver must stop * polling for targets. + * NOTE: This function can be called with targets=NULL and n_targets=0 to + * notify a driver error, meaning that the polling operation cannot complete. * IMPORTANT: this function must not be called from an atomic context. * In addition, it must also not be called from a context that would prevent * the NFC Core to call other nfc ops entry point concurrently. @@ -586,13 +588,18 @@ int nfc_targets_found(struct nfc_dev *dev, dev->targets_generation++; kfree(dev->targets); - dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target), - GFP_ATOMIC); + dev->targets = NULL; - if (!dev->targets) { - dev->n_targets = 0; - device_unlock(&dev->dev); - return -ENOMEM; + if (targets) { + dev->targets = kmemdup(targets, + n_targets * sizeof(struct nfc_target), + GFP_ATOMIC); + + if (!dev->targets) { + dev->n_targets = 0; + device_unlock(&dev->dev); + return -ENOMEM; + } } dev->n_targets = n_targets; -- cgit v1.2.3 From 9eb334ac1709e8f135af341ce1dd0e6b4449c6d3 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 11 Jun 2012 15:52:38 +0200 Subject: NFC: nfc_driver_failure() implementation If the device is polling we sent a 0 target found event. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- net/nfc/core.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/core.c b/net/nfc/core.c index 749ee48d3600..00105e77c792 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -663,13 +663,9 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) } EXPORT_SYMBOL(nfc_target_lost); -void nfc_driver_failure(struct nfc_dev *dev, int err) +inline void nfc_driver_failure(struct nfc_dev *dev, int err) { - /* - * TODO: if polling is active, send empty target_found - * or else do whatever makes sense to let user space - * know this device needs to be closed and reinitialized. - */ + nfc_targets_found(dev, NULL, 0); } EXPORT_SYMBOL(nfc_driver_failure); -- cgit v1.2.3 From a10d595b1074d04446f77161eea165e5809e163c Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Tue, 5 Jun 2012 14:42:11 +0200 Subject: NFC: Allow HCI driver to pre-open pipes to some gates Some NFC chips will statically create and open pipes for both standard and proprietary gates. The driver can now pass this information to HCI such that HCI will not attempt to create and open them, but will instead directly use the passed pipe ids. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz --- drivers/nfc/pn544_hci.c | 31 ++++++++++++++++++------------- include/net/nfc/hci.h | 17 ++++++++++++++--- net/nfc/hci/command.c | 8 ++++++-- net/nfc/hci/core.c | 23 +++++++++-------------- net/nfc/hci/hci.h | 5 ----- 5 files changed, 47 insertions(+), 37 deletions(-) (limited to 'net/nfc') diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index 69df6fecb847..c67b55e224e0 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c @@ -108,16 +108,22 @@ enum pn544_state { #define PN544_NFC_WI_MGMT_GATE 0xA1 -static u8 pn544_custom_gates[] = { - PN544_SYS_MGMT_GATE, - PN544_SWP_MGMT_GATE, - PN544_POLLING_LOOP_MGMT_GATE, - PN544_NFC_WI_MGMT_GATE, - PN544_RF_READER_F_GATE, - PN544_RF_READER_JEWEL_GATE, - PN544_RF_READER_ISO15693_GATE, - PN544_RF_READER_NFCIP1_INITIATOR_GATE, - PN544_RF_READER_NFCIP1_TARGET_GATE +static struct nfc_hci_gate pn544_gates[] = { + {NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE}, + {NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE}, + {NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {NFC_HCI_LINK_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE}, + {NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_SYS_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_SWP_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_POLLING_LOOP_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_NFC_WI_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_RF_READER_JEWEL_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_RF_READER_NFCIP1_INITIATOR_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_RF_READER_NFCIP1_TARGET_GATE, NFC_HCI_INVALID_PIPE} }; /* Largest headroom needed for outgoing custom commands */ @@ -849,10 +855,9 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, goto err_rti; } - init_data.gate_count = ARRAY_SIZE(pn544_custom_gates); + init_data.gate_count = ARRAY_SIZE(pn544_gates); - memcpy(init_data.gates, pn544_custom_gates, - ARRAY_SIZE(pn544_custom_gates)); + memcpy(init_data.gates, pn544_gates, sizeof(pn544_gates)); /* * TODO: Session id must include the driver name + some bus addr diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index d25dd9b99877..f5169b04f082 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -44,10 +44,20 @@ struct nfc_hci_ops { struct nfc_target *target); }; -#define NFC_HCI_MAX_CUSTOM_GATES 15 +/* Pipes */ +#define NFC_HCI_INVALID_PIPE 0x80 +#define NFC_HCI_LINK_MGMT_PIPE 0x00 +#define NFC_HCI_ADMIN_PIPE 0x01 + +struct nfc_hci_gate { + u8 gate; + u8 pipe; +}; + +#define NFC_HCI_MAX_CUSTOM_GATES 50 struct nfc_hci_init_data { u8 gate_count; - u8 gates[NFC_HCI_MAX_CUSTOM_GATES]; + struct nfc_hci_gate gates[NFC_HCI_MAX_CUSTOM_GATES]; char session_id[9]; }; @@ -182,7 +192,8 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb); /* connecting to gates and sending hci instructions */ -int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate); +int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, + u8 pipe); int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate); int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev); int nfc_hci_get_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 12cd6f3f77ec..46362ef979db 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c @@ -299,9 +299,9 @@ int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev) } EXPORT_SYMBOL(nfc_hci_disconnect_all_gates); -int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) +int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, + u8 pipe) { - u8 pipe = NFC_HCI_INVALID_PIPE; bool pipe_created = false; int r; @@ -310,6 +310,9 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE) return -EADDRINUSE; + if (pipe != NFC_HCI_INVALID_PIPE) + goto pipe_is_open; + switch (dest_gate) { case NFC_HCI_LINK_MGMT_GATE: pipe = NFC_HCI_LINK_MGMT_PIPE; @@ -335,6 +338,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) return r; } +pipe_is_open: hdev->gate2pipe[dest_gate] = pipe; return 0; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index e6b2df3981b6..4ccc518f56eb 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -315,15 +315,15 @@ static void nfc_hci_cmd_timeout(unsigned long data) } static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, - u8 gates[]) + struct nfc_hci_gate *gates) { int r; - u8 *p = gates; while (gate_count--) { - r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, *p); + r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, + gates->gate, gates->pipe); if (r < 0) return r; - p++; + gates++; } return 0; @@ -333,14 +333,13 @@ static int hci_dev_session_init(struct nfc_hci_dev *hdev) { struct sk_buff *skb = NULL; int r; - u8 hci_gates[] = { /* NFC_HCI_ADMIN_GATE MUST be first */ - NFC_HCI_ADMIN_GATE, NFC_HCI_LOOPBACK_GATE, - NFC_HCI_ID_MGMT_GATE, NFC_HCI_LINK_MGMT_GATE, - NFC_HCI_RF_READER_B_GATE, NFC_HCI_RF_READER_A_GATE - }; + + if (hdev->init_data.gates[0].gate != NFC_HCI_ADMIN_GATE) + return -EPROTO; r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, - NFC_HCI_ADMIN_GATE); + hdev->init_data.gates[0].gate, + hdev->init_data.gates[0].pipe); if (r < 0) goto exit; @@ -368,10 +367,6 @@ static int hci_dev_session_init(struct nfc_hci_dev *hdev) if (r < 0) goto exit; - r = hci_dev_connect_gates(hdev, sizeof(hci_gates), hci_gates); - if (r < 0) - goto disconnect_all; - r = hci_dev_connect_gates(hdev, hdev->init_data.gate_count, hdev->init_data.gates); if (r < 0) diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index d3cde075ba60..fa9a21e92239 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h @@ -132,9 +132,4 @@ void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type, #define NFC_HCI_ANY_E_REG_ACCESS_DENIED 0x0a #define NFC_HCI_ANY_E_PIPE_ACCESS_DENIED 0x0b -/* Pipes */ -#define NFC_HCI_INVALID_PIPE 0x80 -#define NFC_HCI_LINK_MGMT_PIPE 0x00 -#define NFC_HCI_ADMIN_PIPE 0x01 - #endif /* __LOCAL_HCI_H */ -- cgit v1.2.3 From 1155bb617a10a67d7a17d03abeee74c6fc85edf4 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 12 Jun 2012 00:35:50 +0200 Subject: NFC: Add modules alias for NFC sockets Signed-off-by: Samuel Ortiz --- net/nfc/core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/nfc') diff --git a/net/nfc/core.c b/net/nfc/core.c index 00105e77c792..8382fbc92237 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -924,3 +924,4 @@ MODULE_AUTHOR("Lauro Ramos Venancio "); MODULE_DESCRIPTION("NFC Core ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_NFC); -- cgit v1.2.3 From 5df16cad44f13293803ad3fbc4d49ae2c40e1f0f Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 12 Jun 2012 16:54:16 +0200 Subject: NFC: Add netlink module alias for NFC Signed-off-by: Samuel Ortiz --- net/nfc/core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/nfc') diff --git a/net/nfc/core.c b/net/nfc/core.c index 8382fbc92237..ff749794bc5b 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -29,6 +29,8 @@ #include #include +#include + #include "nfc.h" #define VERSION "0.1" @@ -925,3 +927,4 @@ MODULE_DESCRIPTION("NFC Core ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); MODULE_ALIAS_NETPROTO(PF_NFC); +MODULE_ALIAS_GENL_FAMILY(NFC_GENL_NAME); -- cgit v1.2.3 From 025f152046c8a4101a61943ab2065fdf1fa02c0e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 18 Jun 2012 21:38:09 +0200 Subject: NFC: Update LLCP socket target index when getting a connection Getting a valid CONNECT means we have a valid target index. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/llcp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net/nfc') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 5d503eeb15a1..eee4b9286f8d 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -677,6 +677,7 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, new_sock->nfc_protocol = sock->nfc_protocol; new_sock->ssap = sock->ssap; new_sock->dsap = ssap; + new_sock->target_idx = local->target_idx; new_sock->parent = parent; nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE], -- cgit v1.2.3 From 12e5bdfefa45ecacd22c519875d06113f95a26af Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 21 Jun 2012 17:41:42 +0200 Subject: NFC: Fix LLCP getname socket op Set the right target index and use a better socket declaration routine. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/sock.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 05ca5a680071..b08e99d2c715 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -283,22 +283,25 @@ error: return ret; } -static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr, +static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, int *len, int peer) { - struct sockaddr_nfc_llcp *llcp_addr = (struct sockaddr_nfc_llcp *)addr; struct sock *sk = sock->sk; struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); + DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, llcp_addr, uaddr); - pr_debug("%p\n", sk); + pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, + llcp_sock->dsap, llcp_sock->ssap); if (llcp_sock == NULL || llcp_sock->dev == NULL) return -EBADFD; - addr->sa_family = AF_NFC; + uaddr->sa_family = AF_NFC; + *len = sizeof(struct sockaddr_nfc_llcp); llcp_addr->dev_idx = llcp_sock->dev->idx; + llcp_addr->target_idx = llcp_sock->target_idx; llcp_addr->dsap = llcp_sock->dsap; llcp_addr->ssap = llcp_sock->ssap; llcp_addr->service_name_len = llcp_sock->service_name_len; -- cgit v1.2.3 From b8e7a06d9cd4c0e778b1d12cef1ef414e0fb6d7e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 22 Jun 2012 02:04:53 +0200 Subject: NFC: Build LLCP general bytes upon request Drivers will need them before starting a poll or when being activated as targets. Mostly WKS can have changed between device registration and then so we need to re-build the whole array. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/llcp.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index eee4b9286f8d..6812b1e4f025 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -310,21 +310,6 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) mutex_unlock(&local->sdp_lock); } -u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) -{ - struct nfc_llcp_local *local; - - local = nfc_llcp_find_local(dev); - if (local == NULL) { - *general_bytes_len = 0; - return NULL; - } - - *general_bytes_len = local->gb_len; - - return local->gb; -} - static int nfc_llcp_build_gb(struct nfc_llcp_local *local) { u8 *gb_cur, *version_tlv, version, version_length; @@ -386,6 +371,23 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) return 0; } +u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) +{ + struct nfc_llcp_local *local; + + local = nfc_llcp_find_local(dev); + if (local == NULL) { + *general_bytes_len = 0; + return NULL; + } + + nfc_llcp_build_gb(local); + + *general_bytes_len = local->gb_len; + + return local->gb; +} + int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) { struct nfc_llcp_local *local = nfc_llcp_find_local(dev); -- cgit v1.2.3 From 4d22ea1532ba5730b665343e513d813c108c84ff Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 22 Jun 2012 14:40:34 +0200 Subject: NFC: Close listening LLCP sockets when the device is gone When the MAC link goes down, we should only keep the bound sockets alive. They will be closed by sock_release or when the underlying NFC device is moving away. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/llcp.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 6812b1e4f025..0c8d25e53ff6 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -45,7 +45,7 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk) write_unlock(&l->lock); } -static void nfc_llcp_socket_release(struct nfc_llcp_local *local) +static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) { struct sock *sk; struct hlist_node *node, *tmp; @@ -78,6 +78,11 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) sock_orphan(accept_sk); } + + if (listen == true) { + release_sock(sk); + continue; + } } sk->sk_state = LLCP_CLOSED; @@ -106,7 +111,7 @@ static void local_release(struct kref *ref) local = container_of(ref, struct nfc_llcp_local, ref); list_del(&local->list); - nfc_llcp_socket_release(local); + nfc_llcp_socket_release(local, false); del_timer_sync(&local->link_timer); skb_queue_purge(&local->tx_queue); destroy_workqueue(local->tx_wq); @@ -991,7 +996,7 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) nfc_llcp_clear_sdp(local); /* Close and purge all existing sockets */ - nfc_llcp_socket_release(local); + nfc_llcp_socket_release(local, true); } void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, -- cgit v1.2.3 From cbbf472181bd5d6229decda96b34b0c2bbcb3050 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 22 Jun 2012 14:48:11 +0200 Subject: NFC: Release LLCP SAP when the owner is released The LLCP SAP should only be freed when the socket owning it is released. As long as the socket is alive, the SAP should be reserved in order to e.g. send the right wks array when bringing the MAC up. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/llcp.c | 13 ------------- net/nfc/llcp/llcp.h | 3 +++ net/nfc/llcp/sock.c | 9 ++++++++- 3 files changed, 11 insertions(+), 14 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 0c8d25e53ff6..1031abd13fc2 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -131,17 +131,6 @@ int nfc_llcp_local_put(struct nfc_llcp_local *local) return kref_put(&local->ref, local_release); } -static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local) -{ - mutex_lock(&local->sdp_lock); - - local->local_wks = 0; - local->local_sdp = 0; - local->local_sap = 0; - - mutex_unlock(&local->sdp_lock); -} - static void nfc_llcp_timeout_work(struct work_struct *work) { struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, @@ -993,8 +982,6 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) if (local == NULL) return; - nfc_llcp_clear_sdp(local); - /* Close and purge all existing sockets */ nfc_llcp_socket_release(local, true); } diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 7286c86982ff..374cc4779af4 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -113,6 +113,9 @@ struct nfc_llcp_sock { /* Is the remote peer ready to receive */ u8 remote_ready; + /* Reserved source SAP */ + u8 reserved_ssap; + struct sk_buff_head tx_queue; struct sk_buff_head tx_pending_queue; struct sk_buff_head tx_backlog_queue; diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index b08e99d2c715..211cb234f7a3 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -124,6 +124,8 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) if (llcp_sock->ssap == LLCP_MAX_SAP) goto put_dev; + llcp_sock->reserved_ssap = llcp_sock->ssap; + nfc_llcp_sock_link(&local->sockets, sk); pr_debug("Socket bound to SAP %d\n", llcp_sock->ssap); @@ -409,7 +411,8 @@ static int llcp_sock_release(struct socket *sock) } } - nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); + if (llcp_sock->reserved_ssap < LLCP_SAP_MAX) + nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); release_sock(sk); @@ -489,6 +492,9 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, ret = -ENOMEM; goto put_dev; } + + llcp_sock->reserved_ssap = llcp_sock->ssap; + if (addr->service_name_len == 0) llcp_sock->dsap = addr->dsap; else @@ -690,6 +696,7 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp) llcp_sock->send_n = llcp_sock->send_ack_n = 0; llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; llcp_sock->remote_ready = 1; + llcp_sock->reserved_ssap = LLCP_SAP_MAX; skb_queue_head_init(&llcp_sock->tx_queue); skb_queue_head_init(&llcp_sock->tx_pending_queue); skb_queue_head_init(&llcp_sock->tx_backlog_queue); -- cgit v1.2.3 From 8b7e8eda58cc09974708dcc6db4c202c419d6cd9 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 22 Jun 2012 15:32:20 +0200 Subject: NFC: Forbid LLCP service name reusing This patch fixes a typo and return the correct error when trying to bind 2 sockets to the same service name. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/sock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/nfc') diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 211cb234f7a3..e5d80142b825 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -121,8 +121,10 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) GFP_KERNEL); llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock); - if (llcp_sock->ssap == LLCP_MAX_SAP) + if (llcp_sock->ssap == LLCP_SAP_MAX) { + ret = -EADDRINUSE; goto put_dev; + } llcp_sock->reserved_ssap = llcp_sock->ssap; -- cgit v1.2.3 From ebbb16d9ebbdf08aaf2963b7993d0b4a9e41b15e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 22 Jun 2012 17:15:20 +0200 Subject: NFC: Forbid SSAP binding to a not well known LLCP service With not Well Known Services there is no guarantees as to which SSAP the server will be listening on, so there is no reason to support binding to a specific source SAP. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/llcp.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 1031abd13fc2..9ab17ec50ce7 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -234,24 +234,12 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, return LLCP_WKS_NUM_SAP + ssap; - } else if (sock->ssap != 0) { - if (sock->ssap < LLCP_WKS_NUM_SAP) { - if (!test_bit(sock->ssap, &local->local_wks)) { - set_bit(sock->ssap, &local->local_wks); - mutex_unlock(&local->sdp_lock); - - return sock->ssap; - } - - } else if (sock->ssap < LLCP_SDP_NUM_SAP) { - if (!test_bit(sock->ssap - LLCP_WKS_NUM_SAP, - &local->local_sdp)) { - set_bit(sock->ssap - LLCP_WKS_NUM_SAP, - &local->local_sdp); - mutex_unlock(&local->sdp_lock); + } else if (sock->ssap != 0 && sock->ssap < LLCP_WKS_NUM_SAP) { + if (!test_bit(sock->ssap, &local->local_wks)) { + set_bit(sock->ssap, &local->local_wks); + mutex_unlock(&local->sdp_lock); - return sock->ssap; - } + return sock->ssap; } } -- cgit v1.2.3 From 8f50020ed9b81ba909ce9573f9d05263cdebf502 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Mon, 25 Jun 2012 15:46:28 +0200 Subject: NFC: LLCP late binding With the LLCP 16 local SAPs we can potentially quickly run out of source SAPs for non well known services. With the so called late binding we will reserve an SAP only when we actually get a client connection for a local service. The SAP will be released once the last client is gone, leaving it available to other services. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/llcp.c | 241 +++++++++++++++++++++++++++++++++++----------------- net/nfc/llcp/llcp.h | 2 + 2 files changed, 166 insertions(+), 77 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 9ab17ec50ce7..6094a2099bd6 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -131,6 +131,44 @@ int nfc_llcp_local_put(struct nfc_llcp_local *local) return kref_put(&local->ref, local_release); } +static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, + u8 ssap, u8 dsap) +{ + struct sock *sk; + struct hlist_node *node; + struct nfc_llcp_sock *llcp_sock; + + pr_debug("ssap dsap %d %d\n", ssap, dsap); + + if (ssap == 0 && dsap == 0) + return NULL; + + read_lock(&local->sockets.lock); + + llcp_sock = NULL; + + sk_for_each(sk, node, &local->sockets.head) { + llcp_sock = nfc_llcp_sock(sk); + + if (llcp_sock->ssap == ssap && llcp_sock->dsap == dsap) + break; + } + + read_unlock(&local->sockets.lock); + + if (llcp_sock == NULL) + return NULL; + + sock_hold(&llcp_sock->sk); + + return llcp_sock; +} + +static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock) +{ + sock_put(&sock->sk); +} + static void nfc_llcp_timeout_work(struct work_struct *work) { struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, @@ -191,6 +229,51 @@ static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len) return -EINVAL; } +static +struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local, + u8 *sn, size_t sn_len) +{ + struct sock *sk; + struct hlist_node *node; + struct nfc_llcp_sock *llcp_sock, *tmp_sock; + + pr_debug("sn %zd %p\n", sn_len, sn); + + if (sn == NULL || sn_len == 0) + return NULL; + + read_lock(&local->sockets.lock); + + llcp_sock = NULL; + + sk_for_each(sk, node, &local->sockets.head) { + tmp_sock = nfc_llcp_sock(sk); + + pr_debug("llcp sock %p\n", tmp_sock); + + if (tmp_sock->sk.sk_state != LLCP_LISTEN) + continue; + + if (tmp_sock->service_name == NULL || + tmp_sock->service_name_len == 0) + continue; + + if (tmp_sock->service_name_len != sn_len) + continue; + + if (memcmp(sn, tmp_sock->service_name, sn_len) == 0) { + llcp_sock = tmp_sock; + break; + } + } + + read_unlock(&local->sockets.lock); + + pr_debug("Found llcp sock %p\n", llcp_sock); + + return llcp_sock; +} + u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, struct nfc_llcp_sock *sock) { @@ -217,22 +300,19 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, } /* - * This is not a well known service, - * we should try to find a local SDP free spot + * Check if there already is a non WKS socket bound + * to this service name. */ - ssap = find_first_zero_bit(&local->local_sdp, LLCP_SDP_NUM_SAP); - if (ssap == LLCP_SDP_NUM_SAP) { + if (nfc_llcp_sock_from_sn(local, sock->service_name, + sock->service_name_len) != NULL) { mutex_unlock(&local->sdp_lock); return LLCP_SAP_MAX; } - pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap); - - set_bit(ssap, &local->local_sdp); mutex_unlock(&local->sdp_lock); - return LLCP_WKS_NUM_SAP + ssap; + return LLCP_SDP_UNBOUND; } else if (sock->ssap != 0 && sock->ssap < LLCP_WKS_NUM_SAP) { if (!test_bit(sock->ssap, &local->local_wks)) { @@ -276,8 +356,34 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) local_ssap = ssap; sdp = &local->local_wks; } else if (ssap < LLCP_LOCAL_NUM_SAP) { + atomic_t *client_cnt; + local_ssap = ssap - LLCP_WKS_NUM_SAP; sdp = &local->local_sdp; + client_cnt = &local->local_sdp_cnt[local_ssap]; + + pr_debug("%d clients\n", atomic_read(client_cnt)); + + mutex_lock(&local->sdp_lock); + + if (atomic_dec_and_test(client_cnt)) { + struct nfc_llcp_sock *l_sock; + + pr_debug("No more clients for SAP %d\n", ssap); + + clear_bit(local_ssap, sdp); + + /* Find the listening sock and set it back to UNBOUND */ + l_sock = nfc_llcp_sock_get(local, ssap, LLCP_SAP_SDP); + if (l_sock) { + l_sock->ssap = LLCP_SDP_UNBOUND; + nfc_llcp_sock_put(l_sock); + } + } + + mutex_unlock(&local->sdp_lock); + + return; } else if (ssap < LLCP_MAX_SAP) { local_ssap = ssap - LLCP_LOCAL_NUM_SAP; sdp = &local->local_sap; @@ -292,6 +398,28 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) mutex_unlock(&local->sdp_lock); } +static u8 nfc_llcp_reserve_sdp_ssap(struct nfc_llcp_local *local) +{ + u8 ssap; + + mutex_lock(&local->sdp_lock); + + ssap = find_first_zero_bit(&local->local_sdp, LLCP_SDP_NUM_SAP); + if (ssap == LLCP_SDP_NUM_SAP) { + mutex_unlock(&local->sdp_lock); + + return LLCP_SAP_MAX; + } + + pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap); + + set_bit(ssap, &local->local_sdp); + + mutex_unlock(&local->sdp_lock); + + return LLCP_WKS_NUM_SAP + ssap; +} + static int nfc_llcp_build_gb(struct nfc_llcp_local *local) { u8 *gb_cur, *version_tlv, version, version_length; @@ -493,74 +621,12 @@ out: return llcp_sock; } -static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, - u8 ssap, u8 dsap) -{ - struct sock *sk; - struct hlist_node *node; - struct nfc_llcp_sock *llcp_sock; - - pr_debug("ssap dsap %d %d\n", ssap, dsap); - - if (ssap == 0 && dsap == 0) - return NULL; - - read_lock(&local->sockets.lock); - - llcp_sock = NULL; - - sk_for_each(sk, node, &local->sockets.head) { - llcp_sock = nfc_llcp_sock(sk); - - if (llcp_sock->ssap == ssap && - llcp_sock->dsap == dsap) - break; - } - - read_unlock(&local->sockets.lock); - - if (llcp_sock == NULL) - return NULL; - - sock_hold(&llcp_sock->sk); - - return llcp_sock; -} - static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, u8 *sn, size_t sn_len) { - struct sock *sk; - struct hlist_node *node; struct nfc_llcp_sock *llcp_sock; - pr_debug("sn %zd\n", sn_len); - - if (sn == NULL || sn_len == 0) - return NULL; - - read_lock(&local->sockets.lock); - - llcp_sock = NULL; - - sk_for_each(sk, node, &local->sockets.head) { - llcp_sock = nfc_llcp_sock(sk); - - if (llcp_sock->sk.sk_state != LLCP_LISTEN) - continue; - - if (llcp_sock->service_name == NULL || - llcp_sock->service_name_len == 0) - continue; - - if (llcp_sock->service_name_len != sn_len) - continue; - - if (memcmp(sn, llcp_sock->service_name, sn_len) == 0) - break; - } - - read_unlock(&local->sockets.lock); + llcp_sock = nfc_llcp_sock_from_sn(local, sn, sn_len); if (llcp_sock == NULL) return NULL; @@ -570,11 +636,6 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, return llcp_sock; } -static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock) -{ - sock_put(&sock->sk); -} - static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len) { u8 *tlv = &skb->data[2], type, length; @@ -646,6 +707,21 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, goto fail; } + if (sock->ssap == LLCP_SDP_UNBOUND) { + u8 ssap = nfc_llcp_reserve_sdp_ssap(local); + + pr_debug("First client, reserving %d\n", ssap); + + if (ssap == LLCP_SAP_MAX) { + reason = LLCP_DM_REJ; + release_sock(&sock->sk); + sock_put(&sock->sk); + goto fail; + } + + sock->ssap = ssap; + } + new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC); if (new_sk == NULL) { reason = LLCP_DM_REJ; @@ -659,10 +735,21 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, new_sock->local = nfc_llcp_local_get(local); new_sock->miu = local->remote_miu; new_sock->nfc_protocol = sock->nfc_protocol; - new_sock->ssap = sock->ssap; new_sock->dsap = ssap; new_sock->target_idx = local->target_idx; new_sock->parent = parent; + new_sock->ssap = sock->ssap; + if (sock->ssap < LLCP_LOCAL_NUM_SAP && sock->ssap >= LLCP_WKS_NUM_SAP) { + atomic_t *client_count; + + pr_debug("reserved_ssap %d for %p\n", sock->ssap, new_sock); + + client_count = + &local->local_sdp_cnt[sock->ssap - LLCP_WKS_NUM_SAP]; + + atomic_inc(client_count); + new_sock->reserved_ssap = sock->ssap; + } nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE], skb->len - LLCP_HEADER_SIZE); diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 374cc4779af4..83b8bba5a280 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -37,6 +37,7 @@ enum llcp_state { #define LLCP_LOCAL_NUM_SAP 32 #define LLCP_LOCAL_SAP_OFFSET (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP) #define LLCP_MAX_SAP (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP + LLCP_LOCAL_NUM_SAP) +#define LLCP_SDP_UNBOUND (LLCP_MAX_SAP + 1) struct nfc_llcp_sock; @@ -69,6 +70,7 @@ struct nfc_llcp_local { unsigned long local_wks; /* Well known services */ unsigned long local_sdp; /* Local services */ unsigned long local_sap; /* Local SAPs, not available for discovery */ + atomic_t local_sdp_cnt[LLCP_SDP_NUM_SAP]; /* local */ u8 gb[NFC_MAX_GT_LEN]; -- cgit v1.2.3 From 5c0560b7a5c662ce5fef6ddd52f7bc8d38ad1907 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 26 Jun 2012 16:13:29 +0200 Subject: NFC: Handle LLCP Disconnected Mode frames When receiving such frame, the sockets waiting for a connection to finish should be woken up. Connecting to an unbound LLCP service will trigger a DM as a response. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/llcp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'net/nfc') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 6094a2099bd6..f3bc0a9efb37 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -958,6 +958,45 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) nfc_llcp_sock_put(llcp_sock); } +static void nfc_llcp_recv_dm(struct nfc_llcp_local *local, struct sk_buff *skb) +{ + struct nfc_llcp_sock *llcp_sock; + struct sock *sk; + u8 dsap, ssap, reason; + + dsap = nfc_llcp_dsap(skb); + ssap = nfc_llcp_ssap(skb); + reason = skb->data[2]; + + pr_debug("%d %d reason %d\n", ssap, dsap, reason); + + switch (reason) { + case LLCP_DM_NOBOUND: + case LLCP_DM_REJ: + llcp_sock = nfc_llcp_connecting_sock_get(local, dsap); + break; + + default: + llcp_sock = nfc_llcp_sock_get(local, dsap, ssap); + break; + } + + if (llcp_sock == NULL) { + pr_err("Invalid DM\n"); + return; + } + + sk = &llcp_sock->sk; + + sk->sk_err = ENXIO; + sk->sk_state = LLCP_CLOSED; + sk->sk_state_change(sk); + + nfc_llcp_sock_put(llcp_sock); + + return; +} + static void nfc_llcp_rx_work(struct work_struct *work) { struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, @@ -1001,6 +1040,11 @@ static void nfc_llcp_rx_work(struct work_struct *work) nfc_llcp_recv_cc(local, skb); break; + case LLCP_PDU_DM: + pr_debug("DM\n"); + nfc_llcp_recv_dm(local, skb); + break; + case LLCP_PDU_I: case LLCP_PDU_RR: case LLCP_PDU_RNR: -- cgit v1.2.3 From 1550bf2d59a5ab74c5c14f2e65ed83516ca7d74d Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 27 Jun 2012 12:23:48 +0200 Subject: NFC: Remove warning from nfc_llcp_local_put The socket local pointer can be NULL when a socket is created but never bound or connected. Reported-by: Sasha Levin Signed-off-by: Samuel Ortiz --- net/nfc/llcp/llcp.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index f3bc0a9efb37..82f0f7588b46 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -123,8 +123,6 @@ static void local_release(struct kref *ref) int nfc_llcp_local_put(struct nfc_llcp_local *local) { - WARN_ON(local == NULL); - if (local == NULL) return 0; -- cgit v1.2.3 From a831b9132065e1aa18acd7910d5f9c164a2f350f Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 28 Jun 2012 16:41:57 +0200 Subject: NFC: Do not return EBUSY when stopping a poll that's already stopped We check for the polling flag before checking if the netlink PID caller match. Signed-off-by: Samuel Ortiz --- net/nfc/netlink.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'net/nfc') diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 03c31db38f12..99bc6f7faa7b 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -634,6 +634,15 @@ static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info) if (!dev) return -ENODEV; + device_lock(&dev->dev); + + if (!dev->polling) { + device_unlock(&dev->dev); + return -EINVAL; + } + + device_unlock(&dev->dev); + mutex_lock(&dev->genl_data.genl_data_mutex); if (dev->genl_data.poll_req_pid != info->snd_pid) { -- cgit v1.2.3 From c66433dc5dda15861dcbac63a97645771d14feb6 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 29 Jun 2012 12:03:55 +0200 Subject: NFC: Dereference LLCP bind socket address after checking for it to be NULL Reported-by: Dan Carpenter Signed-off-by: Samuel Ortiz --- net/nfc/llcp/sock.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/nfc') diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index e5d80142b825..6152d05f8378 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -78,11 +78,11 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) struct sockaddr_nfc_llcp llcp_addr; int len, ret = 0; - pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); - if (!addr || addr->sa_family != AF_NFC) return -EINVAL; + pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); + memset(&llcp_addr, 0, sizeof(llcp_addr)); len = min_t(unsigned int, sizeof(llcp_addr), alen); memcpy(&llcp_addr, addr, len); -- cgit v1.2.3 From 01d719a2287ec34f631800d10f1fad3c134c3e89 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 4 Jul 2012 00:14:04 +0200 Subject: NFC: Add ISO 14443 type B protocol Some devices (e.g. Sony's PaSoRi) can not do type B polling, so we have to make a distinction between ISO14443 type A and B poll modes. Cc: Eric Lapuyade Cc: Ilan Elias Signed-off-by: Samuel Ortiz --- drivers/nfc/nfcwilink.c | 7 ++++--- drivers/nfc/pn533.c | 12 +++++++----- drivers/nfc/pn544_hci.c | 1 + include/linux/nfc.h | 14 ++++++++------ net/nfc/hci/core.c | 2 +- net/nfc/nci/core.c | 5 +++-- net/nfc/nci/ntf.c | 5 ++++- 7 files changed, 28 insertions(+), 18 deletions(-) (limited to 'net/nfc') diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index 1f74a77d040d..e7fd4938f9bc 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c @@ -535,9 +535,10 @@ static int nfcwilink_probe(struct platform_device *pdev) drv->pdev = pdev; protocols = NFC_PROTO_JEWEL_MASK - | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK - | NFC_PROTO_ISO14443_MASK - | NFC_PROTO_NFC_DEP_MASK; + | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK + | NFC_PROTO_ISO14443_MASK + | NFC_PROTO_ISO14443_B_MASK + | NFC_PROTO_NFC_DEP_MASK; drv->ndev = nci_allocate_device(&nfcwilink_ops, protocols, diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 84d8175db818..d606f52fec84 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -49,13 +49,15 @@ #define PN533_DEVICE_STD 0x1 #define PN533_DEVICE_PASORI 0x2 -#define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK \ - | NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK \ - | NFC_PROTO_NFC_DEP_MASK) +#define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ + NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ + NFC_PROTO_NFC_DEP_MASK |\ + NFC_PROTO_ISO14443_B_MASK) #define PN533_NO_TYPE_B_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ NFC_PROTO_MIFARE_MASK | \ NFC_PROTO_FELICA_MASK | \ + NFC_PROTO_ISO14443_MASK | \ NFC_PROTO_NFC_DEP_MASK) static const struct usb_device_id pn533_table[] = { @@ -987,7 +989,7 @@ static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data, if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len)) return -EPROTO; - nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK; + nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_B_MASK; return 0; } @@ -1094,7 +1096,7 @@ static void pn533_poll_create_mod_list(struct pn533 *dev, if (im_protocols & NFC_PROTO_JEWEL_MASK) pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL); - if (im_protocols & NFC_PROTO_ISO14443_MASK) + if (im_protocols & NFC_PROTO_ISO14443_B_MASK) pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B); if (tm_protocols) diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index c67b55e224e0..aa71807189ba 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c @@ -869,6 +869,7 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK | + NFC_PROTO_ISO14443_B_MASK | NFC_PROTO_NFC_DEP_MASK; info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops, diff --git a/include/linux/nfc.h b/include/linux/nfc.h index f4e6dd915b1c..6189f27e305b 100644 --- a/include/linux/nfc.h +++ b/include/linux/nfc.h @@ -136,8 +136,9 @@ enum nfc_attrs { #define NFC_PROTO_FELICA 3 #define NFC_PROTO_ISO14443 4 #define NFC_PROTO_NFC_DEP 5 +#define NFC_PROTO_ISO14443_B 6 -#define NFC_PROTO_MAX 6 +#define NFC_PROTO_MAX 7 /* NFC communication modes */ #define NFC_COMM_ACTIVE 0 @@ -149,11 +150,12 @@ enum nfc_attrs { #define NFC_RF_NONE 2 /* NFC protocols masks used in bitsets */ -#define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL) -#define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE) -#define NFC_PROTO_FELICA_MASK (1 << NFC_PROTO_FELICA) -#define NFC_PROTO_ISO14443_MASK (1 << NFC_PROTO_ISO14443) -#define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP) +#define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL) +#define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE) +#define NFC_PROTO_FELICA_MASK (1 << NFC_PROTO_FELICA) +#define NFC_PROTO_ISO14443_MASK (1 << NFC_PROTO_ISO14443) +#define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP) +#define NFC_PROTO_ISO14443_B_MASK (1 << NFC_PROTO_ISO14443_B) struct sockaddr_nfc { sa_family_t sa_family; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 4ccc518f56eb..36717cebfbb6 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -230,7 +230,7 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) } break; case NFC_HCI_RF_READER_B_GATE: - targets->supported_protocols = NFC_PROTO_ISO14443_MASK; + targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK; break; default: if (hdev->ops->target_from_gate) diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 766a02b1dfa1..5bb4da680427 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -194,7 +194,7 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) } if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && - (protocols & NFC_PROTO_ISO14443_MASK)) { + (protocols & NFC_PROTO_ISO14443_B_MASK)) { cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = NCI_NFC_B_PASSIVE_POLL_MODE; cmd.disc_configs[cmd.num_disc_configs].frequency = 1; @@ -486,7 +486,8 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, param.rf_protocol = NCI_RF_PROTOCOL_T2T; else if (protocol == NFC_PROTO_FELICA) param.rf_protocol = NCI_RF_PROTOCOL_T3T; - else if (protocol == NFC_PROTO_ISO14443) + else if (protocol == NFC_PROTO_ISO14443 || + protocol == NFC_PROTO_ISO14443_B) param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP; else param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP; diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 2ab196a9f228..af7a93b04393 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -170,7 +170,10 @@ static int nci_add_new_protocol(struct nci_dev *ndev, if (rf_protocol == NCI_RF_PROTOCOL_T2T) protocol = NFC_PROTO_MIFARE_MASK; else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) - protocol = NFC_PROTO_ISO14443_MASK; + if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) + protocol = NFC_PROTO_ISO14443_MASK; + else + protocol = NFC_PROTO_ISO14443_B_MASK; else if (rf_protocol == NCI_RF_PROTOCOL_T3T) protocol = NFC_PROTO_FELICA_MASK; else -- cgit v1.2.3 From fe3c094abc2365a226184554501fe0df87fe8271 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 5 Jul 2012 17:43:08 +0200 Subject: NFC: Check for llcp_sock and its device from llcp_sock_getname They both can potentially be NULL. Signed-off-by: Samuel Ortiz --- net/nfc/llcp/sock.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/nfc') diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 6152d05f8378..ddeb9aa398f0 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -294,6 +294,9 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, llcp_addr, uaddr); + if (llcp_sock == NULL || llcp_sock->dev == NULL) + return -EBADFD; + pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, llcp_sock->dsap, llcp_sock->ssap); -- cgit v1.2.3