2012-07-06 19:58:41

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 00/33] NFC updates for 3.6

This is the second (and probably last) NFC pull request for 3.6.
Here are the interesting bits:

- A better error management for the HCI stack.
- An LLCP "late" binding implementation for a better NFC SAP usage. SAPs are
now reserved only when there's a client for it.
- Support for Sony RC-S360 (a.k.a. PaSoRi) pn533 based dongle. We can read and
write NFC tags and also establish a p2p link with this dongle now.
- A few LLCP fixes.

You can either apply those patches manually or pull them from here:

git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-3.0.git tags/nfc-next-3.6-2


Eric Lapuyade (15):
NFC: Prepare asynchronous error management for driver and shdlc
NFC: Removed addressed shdlc TODOs
NFC: Handle SHDLC RSET frames from an SHDLC connected chip
NFC: Remove an impossible HCI error case
NFC: Implement HCP reaggregation allocation error case
NFC: Changed HCI cmd execution completion result to std linux errno
NFC: Driver failure API
NFC: Factorize HCI cmd completion
NFC: Implement HCI driver or internal error management
NFC: Core must test the device polling state inside the device lock
NFC: nfc_targets_found() should accept zero target found
NFC: nfc_driver_failure() implementation
NFC: Error management documentation
NFC: update PN544 HCI driver state when opened/closed
NFC: Allow HCI driver to pre-open pipes to some gates

Samuel Ortiz (18):
NFC: Add modules alias for NFC sockets
NFC: Add netlink module alias for NFC
NFC: Update LLCP socket target index when getting a connection
NFC: Fix LLCP getname socket op
NFC: Build LLCP general bytes upon request
NFC: Close listening LLCP sockets when the device is gone
NFC: Release LLCP SAP when the owner is released
NFC: Forbid LLCP service name reusing
NFC: Forbid SSAP binding to a not well known LLCP service
NFC: LLCP late binding
NFC: Handle LLCP Disconnected Mode frames
NFC: Remove warning from nfc_llcp_local_put
NFC: Do not return EBUSY when stopping a poll that's already stopped
NFC: Dereference LLCP bind socket address after checking for it to be
NULL
NFC: Add initial Sony RC-S360 support to pn533
NFC: Use communicate thru only for PaSoRi when trying to read Felica
tags
NFC: Add ISO 14443 type B protocol
NFC: Check for llcp_sock and its device from llcp_sock_getname

Documentation/nfc/nfc-hci.txt | 33 ++++
drivers/nfc/nfcwilink.c | 7 +-
drivers/nfc/pn533.c | 224 ++++++++++++++++++++++-----
drivers/nfc/pn544_hci.c | 37 +++--
include/linux/nfc.h | 14 +-
include/net/nfc/hci.h | 19 ++-
include/net/nfc/nfc.h | 2 +
net/nfc/core.c | 38 ++++-
net/nfc/hci/command.c | 26 ++--
net/nfc/hci/core.c | 104 ++++++++-----
net/nfc/hci/hci.h | 12 +-
net/nfc/hci/shdlc.c | 38 ++---
net/nfc/llcp/llcp.c | 342 +++++++++++++++++++++++++++--------------
net/nfc/llcp/llcp.h | 5 +
net/nfc/llcp/sock.c | 31 +++-
net/nfc/nci/core.c | 5 +-
net/nfc/nci/ntf.c | 5 +-
net/nfc/netlink.c | 9 ++
18 files changed, 663 insertions(+), 288 deletions(-)

--
1.7.10



2012-07-06 19:59:20

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 11/33] NFC: nfc_targets_found() should accept zero target found

From: Eric Lapuyade <[email protected]>

The semantics for a zero target found event is that the polling operation
could not complete.

Signed-off-by: Eric Lapuyade <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/core.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/net/nfc/core.c b/net/nfc/core.c
index 94ccf07..749ee48 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;
--
1.7.10


2012-07-06 20:00:00

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 22/33] 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 <[email protected]>
---
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(-)

diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 0c8d25e..1031abd 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 7286c86..374cc47 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 b08e99d..211cb23 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);
--
1.7.10


2012-07-06 19:59:45

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 18/33] 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 <[email protected]>
---
net/nfc/llcp/llcp.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 5d503ee..eee4b92 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],
--
1.7.10


2012-07-06 20:00:29

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 30/33] NFC: Add initial Sony RC-S360 support to pn533

Sony RC-S360 is also known as the Sony PaSoRi contactless reader.
Only type 2, 3 and 4 tag reading is supported at the moment.

Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 219 ++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 181 insertions(+), 38 deletions(-)

diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 9ac829e..37786ff 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -38,9 +38,42 @@
#define SCM_VENDOR_ID 0x4E6
#define SCL3711_PRODUCT_ID 0x5591

+#define SONY_VENDOR_ID 0x054c
+#define PASORI_PRODUCT_ID 0x02e1
+
+#define PN533_QUIRKS_TYPE_A BIT(0)
+#define PN533_QUIRKS_TYPE_F BIT(1)
+#define PN533_QUIRKS_DEP BIT(2)
+#define PN533_QUIRKS_RAW_EXCHANGE BIT(3)
+
+#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_NO_TYPE_B_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
+ NFC_PROTO_MIFARE_MASK | \
+ NFC_PROTO_FELICA_MASK | \
+ NFC_PROTO_NFC_DEP_MASK)
+
static const struct usb_device_id pn533_table[] = {
- { USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID) },
- { USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID) },
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = PN533_VENDOR_ID,
+ .idProduct = PN533_PRODUCT_ID,
+ .driver_info = PN533_DEVICE_STD,
+ },
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = SCM_VENDOR_ID,
+ .idProduct = SCL3711_PRODUCT_ID,
+ .driver_info = PN533_DEVICE_STD,
+ },
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE,
+ .idVendor = SONY_VENDOR_ID,
+ .idProduct = PASORI_PRODUCT_ID,
+ .driver_info = PN533_DEVICE_PASORI,
+ },
{ }
};
MODULE_DEVICE_TABLE(usb, pn533_table);
@@ -72,6 +105,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_CMD_GET_FIRMWARE_VERSION 0x02
#define PN533_CMD_RF_CONFIGURATION 0x32
#define PN533_CMD_IN_DATA_EXCHANGE 0x40
+#define PN533_CMD_IN_COMM_THRU 0x42
#define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A
#define PN533_CMD_IN_ATR 0x50
#define PN533_CMD_IN_RELEASE 0x52
@@ -109,6 +143,7 @@ struct pn533_fw_version {
/* PN533_CMD_RF_CONFIGURATION */
#define PN533_CFGITEM_TIMING 0x02
#define PN533_CFGITEM_MAX_RETRIES 0x05
+#define PN533_CFGITEM_PASORI 0x82

#define PN533_CONFIG_TIMING_102 0xb
#define PN533_CONFIG_TIMING_204 0xc
@@ -344,6 +379,8 @@ struct pn533 {
u8 tgt_available_prots;
u8 tgt_active_prot;
u8 tgt_mode;
+
+ u32 device_type;
};

struct pn533_frame {
@@ -1768,13 +1805,31 @@ static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,
}

if (target == true) {
- skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
- out_frame = (struct pn533_frame *) skb->data;
+ switch (dev->device_type) {
+ case PN533_DEVICE_STD:
+ skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
+ out_frame = (struct pn533_frame *) skb->data;
+ pn533_tx_frame_init(out_frame,
+ PN533_CMD_IN_DATA_EXCHANGE);
+ tg = 1;
+ memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame),
+ &tg, sizeof(u8));
+ out_frame->datalen += sizeof(u8);
+ break;
+
+ case PN533_DEVICE_PASORI:
+ skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
+ out_frame = (struct pn533_frame *) skb->data;
+ pn533_tx_frame_init(out_frame, PN533_CMD_IN_COMM_THRU);
+
+ break;
+
+ default:
+ nfc_dev_err(&dev->interface->dev,
+ "Unknown device type %d", dev->device_type);
+ return -EINVAL;
+ }

- pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE);
- tg = 1;
- memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8));
- out_frame->datalen += sizeof(u8);
} else {
skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
out_frame = (struct pn533_frame *) skb->data;
@@ -2101,7 +2156,28 @@ static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
return rc;
}

-struct nfc_ops pn533_nfc_ops = {
+static int pn533_fw_reset(struct pn533 *dev)
+{
+ int rc;
+ u8 *params;
+
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+ pn533_tx_frame_init(dev->out_frame, 0x18);
+
+ params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame);
+ params[0] = 0x1;
+ dev->out_frame->datalen += 1;
+
+ pn533_tx_frame_finish(dev->out_frame);
+
+ rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
+ dev->in_maxlen);
+
+ return rc;
+}
+
+static struct nfc_ops pn533_nfc_ops = {
.dev_up = NULL,
.dev_down = NULL,
.dep_link_up = pn533_dep_link_up,
@@ -2114,6 +2190,84 @@ struct nfc_ops pn533_nfc_ops = {
.tm_send = pn533_tm_send,
};

+static int pn533_setup(struct pn533 *dev)
+{
+ struct pn533_config_max_retries max_retries;
+ struct pn533_config_timing timing;
+ u8 pasori_cfg[3] = {0x08, 0x01, 0x08};
+ int rc;
+
+ switch (dev->device_type) {
+ case PN533_DEVICE_STD:
+ max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS;
+ max_retries.mx_rty_psl = 2;
+ max_retries.mx_rty_passive_act =
+ PN533_CONFIG_MAX_RETRIES_NO_RETRY;
+
+ timing.rfu = PN533_CONFIG_TIMING_102;
+ timing.atr_res_timeout = PN533_CONFIG_TIMING_204;
+ timing.dep_timeout = PN533_CONFIG_TIMING_409;
+
+ break;
+
+ case PN533_DEVICE_PASORI:
+ max_retries.mx_rty_atr = 0x2;
+ max_retries.mx_rty_psl = 0x1;
+ max_retries.mx_rty_passive_act =
+ PN533_CONFIG_MAX_RETRIES_NO_RETRY;
+
+ timing.rfu = PN533_CONFIG_TIMING_102;
+ timing.atr_res_timeout = PN533_CONFIG_TIMING_102;
+ timing.dep_timeout = PN533_CONFIG_TIMING_204;
+
+ break;
+
+ default:
+ nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n",
+ dev->device_type);
+ return -EINVAL;
+ }
+
+ rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES,
+ (u8 *)&max_retries, sizeof(max_retries));
+ if (rc) {
+ nfc_dev_err(&dev->interface->dev,
+ "Error on setting MAX_RETRIES config");
+ return rc;
+ }
+
+
+ rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING,
+ (u8 *)&timing, sizeof(timing));
+ if (rc) {
+ nfc_dev_err(&dev->interface->dev,
+ "Error on setting RF timings");
+ return rc;
+ }
+
+ switch (dev->device_type) {
+ case PN533_DEVICE_STD:
+ break;
+
+ case PN533_DEVICE_PASORI:
+ pn533_fw_reset(dev);
+
+ rc = pn533_set_configuration(dev, PN533_CFGITEM_PASORI,
+ pasori_cfg, 3);
+ if (rc) {
+ nfc_dev_err(&dev->interface->dev,
+ "Error while settings PASORI config");
+ return rc;
+ }
+
+ pn533_fw_reset(dev);
+
+ break;
+ }
+
+ return 0;
+}
+
static int pn533_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -2121,8 +2275,6 @@ static int pn533_probe(struct usb_interface *interface,
struct pn533 *dev;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
- struct pn533_config_max_retries max_retries;
- struct pn533_config_timing timing;
int in_endpoint = 0;
int out_endpoint = 0;
int rc = -ENOMEM;
@@ -2208,10 +2360,22 @@ static int pn533_probe(struct usb_interface *interface,
nfc_dev_info(&dev->interface->dev, "NXP PN533 firmware ver %d.%d now"
" attached", fw_ver->ver, fw_ver->rev);

- protocols = NFC_PROTO_JEWEL_MASK
- | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
- | NFC_PROTO_ISO14443_MASK
- | NFC_PROTO_NFC_DEP_MASK;
+ dev->device_type = id->driver_info;
+ switch (dev->device_type) {
+ case PN533_DEVICE_STD:
+ protocols = PN533_ALL_PROTOCOLS;
+ break;
+
+ case PN533_DEVICE_PASORI:
+ protocols = PN533_NO_TYPE_B_PROTOCOLS;
+ break;
+
+ default:
+ nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n",
+ dev->device_type);
+ rc = -EINVAL;
+ goto destroy_wq;
+ }

dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols,
PN533_CMD_DATAEXCH_HEAD_LEN,
@@ -2226,30 +2390,9 @@ static int pn533_probe(struct usb_interface *interface,
if (rc)
goto free_nfc_dev;

- max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS;
- max_retries.mx_rty_psl = 2;
- max_retries.mx_rty_passive_act = PN533_CONFIG_MAX_RETRIES_NO_RETRY;
-
- rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES,
- (u8 *) &max_retries, sizeof(max_retries));
-
- if (rc) {
- nfc_dev_err(&dev->interface->dev, "Error on setting MAX_RETRIES"
- " config");
- goto unregister_nfc_dev;
- }
-
- timing.rfu = PN533_CONFIG_TIMING_102;
- timing.atr_res_timeout = PN533_CONFIG_TIMING_204;
- timing.dep_timeout = PN533_CONFIG_TIMING_409;
-
- rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING,
- (u8 *) &timing, sizeof(timing));
- if (rc) {
- nfc_dev_err(&dev->interface->dev,
- "Error on setting RF timings");
+ rc = pn533_setup(dev);
+ if (rc)
goto unregister_nfc_dev;
- }

return 0;

--
1.7.10


2012-07-06 19:59:05

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 07/33] NFC: Driver failure API

From: Eric Lapuyade <[email protected]>

This API should be used by drivers, HCI, SHDLC or NCI stacks to report an
unrecoverable error.

Signed-off-by: Eric Lapuyade <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
include/net/nfc/nfc.h | 2 ++
net/nfc/core.c | 10 ++++++++++
2 files changed, 12 insertions(+)

diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index 180964b..6431f5e 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 4177bb5..32f2832 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);
--
1.7.10


2012-07-06 19:58:42

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 01/33] NFC: Prepare asynchronous error management for driver and shdlc

From: Eric Lapuyade <[email protected]>

Signed-off-by: Eric Lapuyade <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
include/net/nfc/hci.h | 2 ++
net/nfc/hci/core.c | 8 ++++++++
net/nfc/hci/shdlc.c | 19 +++++++++++--------
3 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h
index e30e6a8..d25dd9b 100644
--- a/include/net/nfc/hci.h
+++ b/include/net/nfc/hci.h
@@ -112,6 +112,8 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev);
void nfc_hci_set_clientdata(struct nfc_hci_dev *hdev, void *clientdata);
void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev);

+void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err);
+
/* Host IDs */
#define NFC_HCI_HOST_CONTROLLER_ID 0x00
#define NFC_HCI_TERMINAL_HOST_ID 0x01
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index a8b0b71..1dc6485 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 6b836e6..d7c74d1 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:
--
1.7.10


2012-07-06 19:59:37

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 12/33] NFC: nfc_driver_failure() implementation

From: Eric Lapuyade <[email protected]>

If the device is polling we sent a 0 target found event.

Signed-off-by: Eric Lapuyade <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/core.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/net/nfc/core.c b/net/nfc/core.c
index 749ee48..00105e7 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);

--
1.7.10


2012-07-06 19:59:35

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 10/33] NFC: Core must test the device polling state inside the device lock

From: Eric Lapuyade <[email protected]>

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 <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/core.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/nfc/core.c b/net/nfc/core.c
index 32f2832..94ccf07 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);
--
1.7.10


2012-07-06 19:58:57

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 05/33] NFC: Implement HCP reaggregation allocation error case

From: Eric Lapuyade <[email protected]>

We can now report an ENOMEM error up to the HCI layer.

Signed-off-by: Eric Lapuyade <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/hci/core.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 1a009d5..7d4fdbc 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;
--
1.7.10


2012-07-06 19:59:57

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 21/33] 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 <[email protected]>
---
net/nfc/llcp/llcp.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 6812b1e..0c8d25e 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,
--
1.7.10


2012-07-06 19:59:42

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 17/33] NFC: Add netlink module alias for NFC

Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/core.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/net/nfc/core.c b/net/nfc/core.c
index 8382fbc..ff74979 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -29,6 +29,8 @@
#include <linux/slab.h>
#include <linux/nfc.h>

+#include <net/genetlink.h>
+
#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);
--
1.7.10


2012-07-06 19:59:53

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 20/33] 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 <[email protected]>
---
net/nfc/llcp/llcp.c | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index eee4b92..6812b1e 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);
--
1.7.10


2012-07-06 19:59:12

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 09/33] NFC: Implement HCI driver or internal error management

From: Eric Lapuyade <[email protected]>

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 <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/hci/core.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 9a1a12f..e6b2df3 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)
--
1.7.10


2012-07-06 19:59:09

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 08/33] NFC: Factorize HCI cmd completion

From: Eric Lapuyade <[email protected]>

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 <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/hci/core.c | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 5be7405..9a1a12f 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);
--
1.7.10


2012-07-06 20:00:33

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 31/33] NFC: Use communicate thru only for PaSoRi when trying to read Felica tags

Otherwise DATA_EXCHANGE seems to be just fine.

Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 37786ff..84d8175 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -1806,7 +1806,17 @@ static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,

if (target == true) {
switch (dev->device_type) {
- case PN533_DEVICE_STD:
+ case PN533_DEVICE_PASORI:
+ if (dev->tgt_active_prot == NFC_PROTO_FELICA) {
+ skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
+ out_frame = (struct pn533_frame *) skb->data;
+ pn533_tx_frame_init(out_frame,
+ PN533_CMD_IN_COMM_THRU);
+
+ break;
+ }
+
+ default:
skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
out_frame = (struct pn533_frame *) skb->data;
pn533_tx_frame_init(out_frame,
@@ -1815,19 +1825,8 @@ static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,
memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame),
&tg, sizeof(u8));
out_frame->datalen += sizeof(u8);
- break;
-
- case PN533_DEVICE_PASORI:
- skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1);
- out_frame = (struct pn533_frame *) skb->data;
- pn533_tx_frame_init(out_frame, PN533_CMD_IN_COMM_THRU);

break;
-
- default:
- nfc_dev_err(&dev->interface->dev,
- "Unknown device type %d", dev->device_type);
- return -EINVAL;
}

} else {
--
1.7.10


2012-07-06 20:00:18

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 27/33] 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 <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/llcp.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index f3bc0a9..82f0f75 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;

--
1.7.10


2012-07-06 20:00:11

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 25/33] 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 <[email protected]>
---
net/nfc/llcp/llcp.c | 241 +++++++++++++++++++++++++++++++++++----------------
net/nfc/llcp/llcp.h | 2 +
2 files changed, 166 insertions(+), 77 deletions(-)

diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 9ab17ec..6094a20 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 374cc47..83b8bba 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];
--
1.7.10


2012-07-06 20:00:40

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 33/33] NFC: Check for llcp_sock and its device from llcp_sock_getname

They both can potentially be NULL.

Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/sock.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index 6152d05..ddeb9aa 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);

--
1.7.10


2012-07-06 19:58:54

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 04/33] NFC: Remove an impossible HCI error case

From: Eric Lapuyade <[email protected]>

nfc_hci_recv_frame can not be called with a NULL skb.

Signed-off-by: Eric Lapuyade <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/hci/core.c | 10 ----------
1 file changed, 10 deletions(-)

diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 1dc6485..1a009d5 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);
--
1.7.10


2012-07-06 20:00:04

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 23/33] 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 <[email protected]>
---
net/nfc/llcp/sock.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index 211cb23..e5d8014 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;

--
1.7.10


2012-07-06 19:58:47

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 02/33] NFC: Removed addressed shdlc TODOs

From: Eric Lapuyade <[email protected]>

The questions asked in the comments have been answered and addressed.

Signed-off-by: Eric Lapuyade <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/hci/shdlc.c | 11 -----------
1 file changed, 11 deletions(-)

diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c
index d7c74d1..18d1536 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);

--
1.7.10


2012-07-06 19:59:01

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 06/33] NFC: Changed HCI cmd execution completion result to std linux errno

From: Eric Lapuyade <[email protected]>

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 <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
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(-)

diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c
index 8729abf..12cd6f3 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 7d4fdbc..5be7405 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 45f2fe4..d3cde07 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 {
--
1.7.10


2012-07-06 20:00:07

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 24/33] 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 <[email protected]>
---
net/nfc/llcp/llcp.c | 22 +++++-----------------
1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 1031abd..9ab17ec 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;
}
}

--
1.7.10


2012-07-06 19:59:31

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 14/33] NFC: update PN544 HCI driver state when opened/closed

From: Eric Lapuyade <[email protected]>

Signed-off-by: Eric Lapuyade <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn544_hci.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c
index 457eac3..69df6fe 100644
--- a/drivers/nfc/pn544_hci.c
+++ b/drivers/nfc/pn544_hci.c
@@ -377,6 +377,9 @@ static int pn544_hci_open(struct nfc_shdlc *shdlc)

r = pn544_hci_enable(info, HCI_MODE);

+ if (r == 0)
+ info->state = PN544_ST_READY;
+
out:
mutex_unlock(&info->info_lock);
return r;
@@ -393,6 +396,8 @@ static void pn544_hci_close(struct nfc_shdlc *shdlc)

pn544_hci_disable(info);

+ info->state = PN544_ST_COLD;
+
out:
mutex_unlock(&info->info_lock);
}
--
1.7.10


2012-07-06 19:59:49

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 19/33] NFC: Fix LLCP getname socket op

Set the right target index and use a better socket declaration routine.

Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/sock.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index 05ca5a6..b08e99d 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;
--
1.7.10


2012-07-06 20:00:15

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 26/33] 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 <[email protected]>
---
net/nfc/llcp/llcp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)

diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 6094a20..f3bc0a9 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:
--
1.7.10


2012-07-06 20:00:37

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 32/33] 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 <[email protected]>
Cc: Ilan Elias <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
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(-)

diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c
index 1f74a77..e7fd493 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 84d8175..d606f52 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 c67b55e..aa71807 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 f4e6dd9..6189f27 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 4ccc518..36717ce 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 766a02b..5bb4da6 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 2ab196a..af7a93b 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
--
1.7.10


2012-07-06 19:59:35

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 15/33] NFC: Allow HCI driver to pre-open pipes to some gates

From: Eric Lapuyade <[email protected]>

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 <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
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(-)

diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c
index 69df6fe..c67b55e 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 d25dd9b..f5169b0 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 12cd6f3..46362ef 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 e6b2df3..4ccc518 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 d3cde07..fa9a21e 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 */
--
1.7.10


2012-07-06 19:58:50

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 03/33] NFC: Handle SHDLC RSET frames from an SHDLC connected chip

From: Eric Lapuyade <[email protected]>

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 <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/hci/shdlc.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c
index 18d1536..6f840c1 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:
--
1.7.10


2012-07-06 20:00:22

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 28/33] 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 <[email protected]>
---
net/nfc/netlink.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 03c31db..99bc6f7 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) {
--
1.7.10


2012-07-06 19:59:39

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 16/33] NFC: Add modules alias for NFC sockets

Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/core.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/net/nfc/core.c b/net/nfc/core.c
index 00105e7..8382fbc 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -924,3 +924,4 @@ MODULE_AUTHOR("Lauro Ramos Venancio <[email protected]>");
MODULE_DESCRIPTION("NFC Core ver " VERSION);
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
+MODULE_ALIAS_NETPROTO(PF_NFC);
--
1.7.10


2012-07-06 20:00:26

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 29/33] NFC: Dereference LLCP bind socket address after checking for it to be NULL

Reported-by: Dan Carpenter <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/sock.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index e5d8014..6152d05 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);
--
1.7.10


2012-07-06 19:59:28

by Samuel Ortiz

[permalink] [raw]
Subject: [PATCH 13/33] NFC: Error management documentation

From: Eric Lapuyade <[email protected]>

Signed-off-by: Eric Lapuyade <[email protected]>
Signed-off-by: Samuel Ortiz <[email protected]>
---
Documentation/nfc/nfc-hci.txt | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)

diff --git a/Documentation/nfc/nfc-hci.txt b/Documentation/nfc/nfc-hci.txt
index 320f933..89a339c 100644
--- a/Documentation/nfc/nfc-hci.txt
+++ b/Documentation/nfc/nfc-hci.txt
@@ -178,3 +178,36 @@ ANY_GET_PARAMETER to the reader A gate to get information on the target
that was discovered).

Typically, such an event will be propagated to NFC Core from MSGRXWQ context.
+
+Error management
+----------------
+
+Errors that occur synchronously with the execution of an NFC Core request are
+simply returned as the execution result of the request. These are easy.
+
+Errors that occur asynchronously (e.g. in a background protocol handling thread)
+must be reported such that upper layers don't stay ignorant that something
+went wrong below and know that expected events will probably never happen.
+Handling of these errors is done as follows:
+
+- driver (pn544) fails to deliver an incoming frame: it stores the error such
+that any subsequent call to the driver will result in this error. Then it calls
+the standard nfc_shdlc_recv_frame() with a NULL argument to report the problem
+above. shdlc stores a EREMOTEIO sticky status, which will trigger SMW to
+report above in turn.
+
+- SMW is basically a background thread to handle incoming and outgoing shdlc
+frames. This thread will also check the shdlc sticky status and report to HCI
+when it discovers it is not able to run anymore because of an unrecoverable
+error that happened within shdlc or below. If the problem occurs during shdlc
+connection, the error is reported through the connect completion.
+
+- HCI: if an internal HCI error happens (frame is lost), or HCI is reported an
+error from a lower layer, HCI will either complete the currently executing
+command with that error, or notify NFC Core directly if no command is executing.
+
+- NFC Core: when NFC Core is notified of an error from below and polling is
+active, it will send a tag discovered event with an empty tag list to the user
+space to let it know that the poll operation will never be able to detect a tag.
+If polling is not active and the error was sticky, lower levels will return it
+at next invocation.
--
1.7.10