Hi John,
This is the first NFC patchset for 3.6. With this one we have:
- Peer to peer target mode support. Peer devices can now detect and activate
us as targets, not only as initiators.
- An LLCP socket handling code simplification. It's simpler and race free now.
- LLCP fixes. Attending the NFC plugfest helped fixed a few LLCP bugs.
- At the NFC plugfest I also found some issues with the pn533 radio and
digital settings. This should be improved now.
- The pn533 also gets a few improvements, like a semaphore to mutex conversion
and a proper polling loop implementation (alternating between target and
initiator modes).
You can either apply those patches manually, or pull it from here:
git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-3.0.git tags/nfc-next-3.6-1
Thanks in advance for merging this code.
Samuel Ortiz (29):
NFC: Take a reference on the LLCP local pointer when creating a
socket
NFC: Socket linked list
NFC: Move LLCP receiver window value to socket structure
NFC: Move LLCP MIU extension value to socket structure
NFC: LLCP's MIUX is 10 bytes long, not 7
NFC: Export LLCP general bytes getter
NFC: Add target mode protocols to the polling loop startup routine
NFC: Implement pn533 target mode polling loop
NFC: Add target mode activation netlink event
NFC: Set the NFC device RF mode appropriately
NFC: Introduce target mode tx ops
NFC: Introduce target mode rx data callback
NFC: Implement the pn533 target mode data fetching routine
NFC: Implement the pn533 target mode Tx op
NFC: Don't hold a NULL connecting LLCP socket lock
NFC: Call the DEP link down ops even when in target mode
NFC: Reset poll mod list when stopping pn533 poll
NFC: Unregister device if pn533 initial configuration fails
NFC: Configure pn533 RF timings
NFC: Add passive initiator data for pn533
NFC: Add type A and type F parameters for pn533 target mode
NFC: Implement pn533 polling loop
NFC: Requeue lost LLCP frames
NFC: Send a receiver ready frame only to reply to an I frame
NFC: Switch to Initiator mode when getting NFC_ATTR_PROTOCOLS
NFC: Destroy LLCP timout workqueue when releasing the link
NFC: Set the proper baud rate when trying to activate pn533 targets
NFC: Convert pn533 from semaphore to mutex
NFC: Monitor pn533 target mode
drivers/nfc/pn533.c | 662 ++++++++++++++++++++++++++++++++++++++---------
drivers/nfc/pn544_hci.c | 10 +-
include/linux/nfc.h | 12 +
include/net/nfc/hci.h | 3 +-
include/net/nfc/nfc.h | 14 +-
include/net/nfc/shdlc.h | 3 +-
net/nfc/core.c | 119 +++++++---
net/nfc/hci/core.c | 13 +-
net/nfc/hci/shdlc.c | 6 +-
net/nfc/llcp/commands.c | 54 +++-
net/nfc/llcp/llcp.c | 421 ++++++++++++++++++------------
net/nfc/llcp/llcp.h | 26 ++-
net/nfc/llcp/sock.c | 47 ++--
net/nfc/nci/core.c | 15 +-
net/nfc/netlink.c | 81 ++++++-
net/nfc/nfc.h | 12 +-
16 files changed, 1106 insertions(+), 392 deletions(-)
--
1.7.9.1
RW can only be fetched from a CONNECT or a CC frame thus making it an
end points specific value, not a link one.
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/commands.c | 45 ++++++++++++++++++++++++++++++++++++++-------
net/nfc/llcp/llcp.c | 21 ++++++++++-----------
net/nfc/llcp/llcp.h | 9 ++++++---
net/nfc/llcp/sock.c | 1 +
4 files changed, 55 insertions(+), 21 deletions(-)
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c
index bf8ae4f..eb51864 100644
--- a/net/nfc/llcp/commands.c
+++ b/net/nfc/llcp/commands.c
@@ -117,8 +117,8 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length)
return tlv;
}
-int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
- u8 *tlv_array, u16 tlv_array_len)
+int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
+ u8 *tlv_array, u16 tlv_array_len)
{
u8 *tlv = tlv_array, type, length, offset = 0;
@@ -149,8 +149,42 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
case LLCP_TLV_OPT:
local->remote_opt = llcp_tlv_opt(tlv);
break;
+ default:
+ pr_err("Invalid gt tlv value 0x%x\n", type);
+ break;
+ }
+
+ offset += length + 2;
+ tlv += length + 2;
+ }
+
+ pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x\n",
+ local->remote_version, local->remote_miu,
+ local->remote_lto, local->remote_opt,
+ local->remote_wks);
+
+ return 0;
+}
+
+int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
+ u8 *tlv_array, u16 tlv_array_len)
+{
+ u8 *tlv = tlv_array, type, length, offset = 0;
+
+ pr_debug("TLV array length %d\n", tlv_array_len);
+
+ if (sock == NULL)
+ return -ENOTCONN;
+
+ while (offset < tlv_array_len) {
+ type = tlv[0];
+ length = tlv[1];
+
+ pr_debug("type 0x%x length %d\n", type, length);
+
+ switch (type) {
case LLCP_TLV_RW:
- local->remote_rw = llcp_tlv_rw(tlv);
+ sock->rw = llcp_tlv_rw(tlv);
break;
case LLCP_TLV_SN:
break;
@@ -163,10 +197,7 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
tlv += length + 2;
}
- pr_debug("version 0x%x miu %d lto %d opt 0x%x wks 0x%x rw %d\n",
- local->remote_version, local->remote_miu,
- local->remote_lto, local->remote_opt,
- local->remote_wks, local->remote_rw);
+ pr_debug("sock %p rw %d\n", sock, sock->rw);
return 0;
}
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 262aa82..d3efc5b 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -406,9 +406,9 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
return -EINVAL;
}
- return nfc_llcp_parse_tlv(local,
- &local->remote_gb[3],
- local->remote_gb_len - 3);
+ return nfc_llcp_parse_gb_tlv(local,
+ &local->remote_gb[3],
+ local->remote_gb_len - 3);
}
static void nfc_llcp_tx_work(struct work_struct *work)
@@ -608,9 +608,6 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
pr_debug("%d %d\n", dsap, ssap);
- nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
- skb->len - LLCP_HEADER_SIZE);
-
if (dsap != LLCP_SAP_SDP) {
sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
if (sock == NULL || sock->sk.sk_state != LLCP_LISTEN) {
@@ -663,6 +660,9 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
new_sock->dsap = ssap;
new_sock->parent = parent;
+ nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE],
+ skb->len - LLCP_HEADER_SIZE);
+
pr_debug("new sock %p sk %p\n", new_sock, &new_sock->sk);
nfc_llcp_sock_link(&local->sockets, new_sk);
@@ -699,11 +699,11 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
pr_debug("Remote ready %d tx queue len %d remote rw %d",
sock->remote_ready, skb_queue_len(&sock->tx_pending_queue),
- local->remote_rw);
+ sock->rw);
/* Try to queue some I frames for transmission */
while (sock->remote_ready &&
- skb_queue_len(&sock->tx_pending_queue) < local->remote_rw) {
+ skb_queue_len(&sock->tx_pending_queue) < sock->rw) {
struct sk_buff *pdu, *pending_pdu;
pdu = skb_dequeue(&sock->tx_queue);
@@ -851,8 +851,8 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
nfc_llcp_sock_link(&local->sockets, sk);
llcp_sock->dsap = ssap;
- nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
- skb->len - LLCP_HEADER_SIZE);
+ nfc_llcp_parse_connection_tlv(llcp_sock, &skb->data[LLCP_HEADER_SIZE],
+ skb->len - LLCP_HEADER_SIZE);
sk->sk_state = LLCP_CONNECTED;
sk->sk_state_change(sk);
@@ -1036,7 +1036,6 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
local->remote_miu = LLCP_DEFAULT_MIU;
local->remote_lto = LLCP_DEFAULT_LTO;
- local->remote_rw = LLCP_DEFAULT_RW;
list_add(&llcp_devices, &local->list);
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h
index 7053304..add03e7 100644
--- a/net/nfc/llcp/llcp.h
+++ b/net/nfc/llcp/llcp.h
@@ -83,7 +83,6 @@ struct nfc_llcp_local {
u16 remote_lto;
u8 remote_opt;
u16 remote_wks;
- u8 remote_rw;
/* sockets array */
struct llcp_sock_list sockets;
@@ -97,10 +96,12 @@ struct nfc_llcp_sock {
u32 target_idx;
u32 nfc_protocol;
+ /* Link parameters */
u8 ssap;
u8 dsap;
char *service_name;
size_t service_name_len;
+ u8 rw;
/* Link variables */
u8 send_n;
@@ -189,8 +190,10 @@ void nfc_llcp_accept_enqueue(struct sock *parent, struct sock *sk);
struct sock *nfc_llcp_accept_dequeue(struct sock *sk, struct socket *newsock);
/* TLV API */
-int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
- u8 *tlv_array, u16 tlv_array_len);
+int nfc_llcp_parse_gb_tlv(struct nfc_llcp_local *local,
+ u8 *tlv_array, u16 tlv_array_len);
+int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
+ u8 *tlv_array, u16 tlv_array_len);
/* Commands API */
void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index 8a60b53..aab077e 100644
--- a/net/nfc/llcp/sock.c
+++ b/net/nfc/llcp/sock.c
@@ -678,6 +678,7 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
llcp_sock->ssap = 0;
llcp_sock->dsap = LLCP_SAP_SDP;
+ llcp_sock->rw = LLCP_DEFAULT_RW;
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;
--
1.7.9.1
When trying to enable a DEP link as a passive initiator, pn533 needs to
provide the polling request command payload.
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 23 ++++++++++++++++++-----
1 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index d976344..806ab3d 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -256,7 +256,7 @@ struct pn533_cmd_jump_dep {
u8 active;
u8 baud;
u8 next;
- u8 gt[];
+ u8 data[];
} __packed;
struct pn533_cmd_jump_dep_response {
@@ -1582,12 +1582,14 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
return 0;
}
+#define PASSIVE_DATA_LEN 5
static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
u8 comm_mode, u8* gb, size_t gb_len)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct pn533_cmd_jump_dep *cmd;
- u8 cmd_len;
+ u8 cmd_len, *data_ptr;
+ u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
@@ -1605,6 +1607,9 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
}
cmd_len = sizeof(struct pn533_cmd_jump_dep) + gb_len;
+ if (comm_mode == NFC_COMM_PASSIVE)
+ cmd_len += PASSIVE_DATA_LEN;
+
cmd = kzalloc(cmd_len, GFP_KERNEL);
if (cmd == NULL)
return -ENOMEM;
@@ -1612,10 +1617,18 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_JUMP_FOR_DEP);
cmd->active = !comm_mode;
- cmd->baud = 0;
+ cmd->next = 0;
+ cmd->baud = 2;
+ data_ptr = cmd->data;
+ if (comm_mode == NFC_COMM_PASSIVE && cmd->baud > 0) {
+ memcpy(data_ptr, passive_data, PASSIVE_DATA_LEN);
+ cmd->next |= 1;
+ data_ptr += PASSIVE_DATA_LEN;
+ }
+
if (gb != NULL && gb_len > 0) {
- cmd->next = 4; /* We have some Gi */
- memcpy(cmd->gt, gb, gb_len);
+ cmd->next |= 4; /* We have some Gi */
+ memcpy(data_ptr, gb, gb_len);
} else {
cmd->next = 0;
}
--
1.7.9.1
We get the right baud rate from the last polled modulation.
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 25 +++++++++++++++++++++++--
1 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index c9ba96c..b97e3c8 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -1629,6 +1629,20 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
return 0;
}
+static int pn533_mod_to_baud(struct pn533 *dev)
+{
+ switch (dev->poll_mod_curr) {
+ case PN533_POLL_MOD_106KBPS_A:
+ return 0;
+ case PN533_POLL_MOD_212KBPS_FELICA:
+ return 1;
+ case PN533_POLL_MOD_424KBPS_FELICA:
+ return 2;
+ default:
+ return -EINVAL;
+ }
+}
+
#define PASSIVE_DATA_LEN 5
static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
u8 comm_mode, u8* gb, size_t gb_len)
@@ -1637,7 +1651,7 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
struct pn533_cmd_jump_dep *cmd;
u8 cmd_len, *data_ptr;
u8 passive_data[PASSIVE_DATA_LEN] = {0x00, 0xff, 0xff, 0x00, 0x3};
- int rc;
+ int rc, baud;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
@@ -1653,6 +1667,13 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
return -EBUSY;
}
+ baud = pn533_mod_to_baud(dev);
+ if (baud < 0) {
+ nfc_dev_err(&dev->interface->dev,
+ "Invalid curr modulation %d", dev->poll_mod_curr);
+ return baud;
+ }
+
cmd_len = sizeof(struct pn533_cmd_jump_dep) + gb_len;
if (comm_mode == NFC_COMM_PASSIVE)
cmd_len += PASSIVE_DATA_LEN;
@@ -1665,7 +1686,7 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
cmd->active = !comm_mode;
cmd->next = 0;
- cmd->baud = 2;
+ cmd->baud = baud;
data_ptr = cmd->data;
if (comm_mode == NFC_COMM_PASSIVE && cmd->baud > 0) {
memcpy(data_ptr, passive_data, PASSIVE_DATA_LEN);
--
1.7.9.1
And rename the initiator mode data exchange ops for consistency sake.
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 8 ++++----
include/net/nfc/nfc.h | 3 ++-
net/nfc/core.c | 37 ++++++++++++++++++++-----------------
net/nfc/hci/core.c | 8 ++++----
net/nfc/nci/core.c | 8 ++++----
5 files changed, 34 insertions(+), 30 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index c6b9bc5..fd94c6f 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -1691,9 +1691,9 @@ error:
return 0;
}
-static int pn533_data_exchange(struct nfc_dev *nfc_dev,
- struct nfc_target *target, struct sk_buff *skb,
- data_exchange_cb_t cb, void *cb_context)
+static int pn533_transceive(struct nfc_dev *nfc_dev,
+ struct nfc_target *target, struct sk_buff *skb,
+ data_exchange_cb_t cb, void *cb_context)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct pn533_frame *out_frame, *in_frame;
@@ -1853,7 +1853,7 @@ struct nfc_ops pn533_nfc_ops = {
.stop_poll = pn533_stop_poll,
.activate_target = pn533_activate_target,
.deactivate_target = pn533_deactivate_target,
- .data_exchange = pn533_data_exchange,
+ .im_transceive = pn533_transceive,
};
static int pn533_probe(struct usb_interface *interface,
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index a6a7b49..45c4c97 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -63,9 +63,10 @@ struct nfc_ops {
u32 protocol);
void (*deactivate_target)(struct nfc_dev *dev,
struct nfc_target *target);
- int (*data_exchange)(struct nfc_dev *dev, struct nfc_target *target,
+ int (*im_transceive)(struct nfc_dev *dev, struct nfc_target *target,
struct sk_buff *skb, data_exchange_cb_t cb,
void *cb_context);
+ int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb);
int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
};
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 722a0c7..76c1e20 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -413,27 +413,30 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
goto error;
}
- if (dev->active_target == NULL) {
- rc = -ENOTCONN;
- kfree_skb(skb);
- goto error;
- }
+ if (dev->rf_mode == NFC_RF_INITIATOR && dev->active_target != NULL) {
+ if (dev->active_target->idx != target_idx) {
+ rc = -EADDRNOTAVAIL;
+ kfree_skb(skb);
+ goto error;
+ }
- if (dev->active_target->idx != target_idx) {
- rc = -EADDRNOTAVAIL;
+ if (dev->ops->check_presence)
+ del_timer_sync(&dev->check_pres_timer);
+
+ rc = dev->ops->im_transceive(dev, dev->active_target, skb, cb,
+ cb_context);
+
+ if (!rc && dev->ops->check_presence)
+ mod_timer(&dev->check_pres_timer, jiffies +
+ msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
+ } else if (dev->rf_mode == NFC_RF_TARGET && dev->ops->tm_send != NULL) {
+ rc = dev->ops->tm_send(dev, skb);
+ } else {
+ rc = -ENOTCONN;
kfree_skb(skb);
goto error;
}
- if (dev->ops->check_presence)
- del_timer_sync(&dev->check_pres_timer);
-
- rc = dev->ops->data_exchange(dev, dev->active_target, skb, cb,
- cb_context);
-
- if (!rc && dev->ops->check_presence)
- mod_timer(&dev->check_pres_timer, jiffies +
- msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
error:
device_unlock(&dev->dev);
@@ -727,7 +730,7 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
struct nfc_dev *dev;
if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
- !ops->deactivate_target || !ops->data_exchange)
+ !ops->deactivate_target || !ops->im_transceive)
return NULL;
if (!supported_protocols)
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 281f3a3..a8b0b71 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -512,9 +512,9 @@ static void hci_deactivate_target(struct nfc_dev *nfc_dev,
{
}
-static int hci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target,
- struct sk_buff *skb, data_exchange_cb_t cb,
- void *cb_context)
+static int hci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
+ struct sk_buff *skb, data_exchange_cb_t cb,
+ void *cb_context)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
int r;
@@ -580,7 +580,7 @@ static struct nfc_ops hci_nfc_ops = {
.stop_poll = hci_stop_poll,
.activate_target = hci_activate_target,
.deactivate_target = hci_deactivate_target,
- .data_exchange = hci_data_exchange,
+ .im_transceive = hci_transceive,
.check_presence = hci_check_presence,
};
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 0f71898..766a02b 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -522,9 +522,9 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev,
}
}
-static int nci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target,
- struct sk_buff *skb,
- data_exchange_cb_t cb, void *cb_context)
+static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
+ struct sk_buff *skb,
+ data_exchange_cb_t cb, void *cb_context)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
int rc;
@@ -557,7 +557,7 @@ static struct nfc_ops nci_nfc_ops = {
.stop_poll = nci_stop_poll,
.activate_target = nci_activate_target,
.deactivate_target = nci_deactivate_target,
- .data_exchange = nci_data_exchange,
+ .im_transceive = nci_transceive,
};
/* ---- Interface to NCI drivers ---- */
--
1.7.9.1
Sending an RR as a reply to another RR is fine but not quite logical.
We should send RRs only as a reply to I frames.
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/llcp.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 0fc60da..3fe68e1 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -810,7 +810,7 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
else if (ptype == LLCP_PDU_RNR)
llcp_sock->remote_ready = false;
- if (nfc_llcp_queue_i_frames(llcp_sock) == 0)
+ if (nfc_llcp_queue_i_frames(llcp_sock) == 0 && ptype == LLCP_PDU_I)
nfc_llcp_send_rr(llcp_sock);
release_sock(sk);
--
1.7.9.1
When receiving a DEP link down event, we should cancel all pending URBs
if we're activated as a target or if we're an initiator.
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 23 ++++++++++++++++++++++-
1 files changed, 22 insertions(+), 1 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 58c1641..9ac829e 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -343,6 +343,7 @@ struct pn533 {
u8 tgt_available_prots;
u8 tgt_active_prot;
+ u8 tgt_mode;
};
struct pn533_frame {
@@ -1158,6 +1159,8 @@ static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg,
if (params_len > 0 && params[0] != 0) {
nfc_tm_deactivated(dev->nfc_dev);
+ dev->tgt_mode = 0;
+
kfree_skb(skb_resp);
return 0;
}
@@ -1245,6 +1248,8 @@ static int pn533_init_target_complete(struct pn533 *dev, void *arg,
return rc;
}
+ dev->tgt_mode = 1;
+
queue_work(dev->wq, &dev->tg_work);
return 0;
@@ -1397,6 +1402,12 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev,
return -EBUSY;
}
+ if (dev->tgt_mode) {
+ nfc_dev_err(&dev->interface->dev,
+ "Cannot poll while already being activated");
+ return -EBUSY;
+ }
+
if (tm_protocols) {
dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len);
if (dev->gb == NULL)
@@ -1725,7 +1736,15 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
pn533_poll_reset_mod_list(dev);
- pn533_deactivate_target(nfc_dev, 0);
+ if (dev->tgt_mode || dev->tgt_active_prot) {
+ pn533_send_ack(dev, GFP_KERNEL);
+ usb_kill_urb(dev->in_urb);
+ }
+
+ dev->tgt_active_prot = 0;
+ dev->tgt_mode = 0;
+
+ skb_queue_purge(&dev->resp_q);
return 0;
}
@@ -1956,6 +1975,8 @@ static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
if (params_len > 0 && params[0] != 0) {
nfc_tm_deactivated(dev->nfc_dev);
+ dev->tgt_mode = 0;
+
return 0;
}
--
1.7.9.1
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 82 +++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 73 insertions(+), 9 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 6a506e2..db40787 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -76,6 +76,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_CMD_TG_INIT_AS_TARGET 0x8c
#define PN533_CMD_TG_GET_DATA 0x86
+#define PN533_CMD_TG_SET_DATA 0x8e
#define PN533_CMD_RESPONSE(cmd) (cmd + 1)
@@ -1630,7 +1631,8 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
return 0;
}
-static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
+static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb,
+ bool target)
{
int payload_len = skb->len;
struct pn533_frame *out_frame;
@@ -1647,14 +1649,20 @@ static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
return -ENOSYS;
}
- skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
- out_frame = (struct pn533_frame *) skb->data;
+ if (target == true) {
+ 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);
+ 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;
+ pn533_tx_frame_init(out_frame, PN533_CMD_TG_SET_DATA);
+ }
- tg = 1;
- memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8));
- out_frame->datalen += sizeof(u8);
/* The data is already in the out_frame, just update the datalen */
out_frame->datalen += payload_len;
@@ -1785,7 +1793,7 @@ static int pn533_transceive(struct nfc_dev *nfc_dev,
goto error;
}
- rc = pn533_data_exchange_tx_frame(dev, skb);
+ rc = pn533_build_tx_frame(dev, skb, true);
if (rc)
goto error;
@@ -1833,6 +1841,61 @@ error:
return rc;
}
+static int pn533_tm_send_complete(struct pn533 *dev, void *arg,
+ u8 *params, int params_len)
+{
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+ if (params_len < 0) {
+ nfc_dev_err(&dev->interface->dev,
+ "Error %d when sending data",
+ params_len);
+
+ return params_len;
+ }
+
+ if (params_len > 0 && params[0] != 0) {
+ nfc_tm_deactivated(dev->nfc_dev);
+
+ return 0;
+ }
+
+ queue_work(dev->wq, &dev->tg_work);
+
+ return 0;
+}
+
+static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
+{
+ struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+ struct pn533_frame *out_frame;
+ int rc;
+
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+ rc = pn533_build_tx_frame(dev, skb, false);
+ if (rc)
+ goto error;
+
+ out_frame = (struct pn533_frame *) skb->data;
+
+ rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame,
+ dev->in_maxlen, pn533_tm_send_complete,
+ NULL, GFP_KERNEL);
+ if (rc) {
+ nfc_dev_err(&dev->interface->dev,
+ "Error %d when trying to send data", rc);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ kfree_skb(skb);
+
+ return rc;
+}
+
static void pn533_wq_mi_recv(struct work_struct *work)
{
struct pn533 *dev = container_of(work, struct pn533, mi_work);
@@ -1853,7 +1916,7 @@ static void pn533_wq_mi_recv(struct work_struct *work)
skb_reserve(skb_cmd, PN533_CMD_DATAEXCH_HEAD_LEN);
- rc = pn533_data_exchange_tx_frame(dev, skb_cmd);
+ rc = pn533_build_tx_frame(dev, skb_cmd, true);
if (rc)
goto error_frame;
@@ -1928,6 +1991,7 @@ struct nfc_ops pn533_nfc_ops = {
.activate_target = pn533_activate_target,
.deactivate_target = pn533_deactivate_target,
.im_transceive = pn533_transceive,
+ .tm_send = pn533_tm_send,
};
static int pn533_probe(struct usb_interface *interface,
--
1.7.9.1
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 6b8a65c..2a7e4e8 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -2112,13 +2112,17 @@ static int pn533_probe(struct usb_interface *interface,
if (rc) {
nfc_dev_err(&dev->interface->dev, "Error on setting MAX_RETRIES"
" config");
- goto free_nfc_dev;
+ goto unregister_nfc_dev;
}
return 0;
+unregister_nfc_dev:
+ nfc_unregister_device(dev->nfc_dev);
+
free_nfc_dev:
nfc_free_device(dev->nfc_dev);
+
destroy_wq:
destroy_workqueue(dev->wq);
error:
--
1.7.9.1
That is needed for keeping backward compatibility with apps using the old
netlink polling API (NFC_ATTR_PROTOCOLS instead of NFC_ATTR_IM_PROTOCOLS).
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/netlink.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 21eaa9b..03c31db 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -597,11 +597,11 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NFC_ATTR_TM_PROTOCOLS])
tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_TM_PROTOCOLS]);
- else if (info->attrs[NFC_ATTR_PROTOCOLS])
- tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
if (info->attrs[NFC_ATTR_IM_PROTOCOLS])
im_protocols = nla_get_u32(info->attrs[NFC_ATTR_IM_PROTOCOLS]);
+ else if (info->attrs[NFC_ATTR_PROTOCOLS])
+ im_protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
dev = nfc_get_device(idx);
if (!dev)
--
1.7.9.1
Simplify the LLCP sockets structure by putting all the connected ones
into a single linked list.
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/llcp.c | 249 ++++++++++++++++++++++++++++-----------------------
net/nfc/llcp/llcp.h | 12 ++-
net/nfc/llcp/sock.c | 32 +++----
3 files changed, 158 insertions(+), 135 deletions(-)
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 0f6dd3a..262aa82 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -31,45 +31,41 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
static struct list_head llcp_devices;
-static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
+void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk)
{
- struct nfc_llcp_sock *parent, *s, *n;
- struct sock *sk, *parent_sk;
- int i;
-
- mutex_lock(&local->socket_lock);
-
- for (i = 0; i < LLCP_MAX_SAP; i++) {
- parent = local->sockets[i];
- if (parent == NULL)
- continue;
-
- /* Release all child sockets */
- list_for_each_entry_safe(s, n, &parent->list, list) {
- list_del_init(&s->list);
- sk = &s->sk;
-
- lock_sock(sk);
+ write_lock(&l->lock);
+ sk_add_node(sk, &l->head);
+ write_unlock(&l->lock);
+}
- if (sk->sk_state == LLCP_CONNECTED)
- nfc_put_device(s->dev);
+void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
+{
+ write_lock(&l->lock);
+ sk_del_node_init(sk);
+ write_unlock(&l->lock);
+}
- sk->sk_state = LLCP_CLOSED;
+static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
+{
+ struct sock *sk;
+ struct hlist_node *node, *tmp;
+ struct nfc_llcp_sock *llcp_sock;
- release_sock(sk);
+ write_lock(&local->sockets.lock);
- sock_orphan(sk);
- }
+ sk_for_each_safe(sk, node, tmp, &local->sockets.head) {
+ llcp_sock = nfc_llcp_sock(sk);
- parent_sk = &parent->sk;
+ lock_sock(sk);
- lock_sock(parent_sk);
+ if (sk->sk_state == LLCP_CONNECTED)
+ nfc_put_device(llcp_sock->dev);
- if (parent_sk->sk_state == LLCP_LISTEN) {
+ if (sk->sk_state == LLCP_LISTEN) {
struct nfc_llcp_sock *lsk, *n;
struct sock *accept_sk;
- list_for_each_entry_safe(lsk, n, &parent->accept_queue,
+ list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue,
accept_queue) {
accept_sk = &lsk->sk;
lock_sock(accept_sk);
@@ -84,17 +80,16 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
}
}
- if (parent_sk->sk_state == LLCP_CONNECTED)
- nfc_put_device(parent->dev);
+ sk->sk_state = LLCP_CLOSED;
- parent_sk->sk_state = LLCP_CLOSED;
+ release_sock(sk);
- release_sock(parent_sk);
+ sock_orphan(sk);
- sock_orphan(parent_sk);
+ sk_del_node_init(sk);
}
- mutex_unlock(&local->socket_lock);
+ write_unlock(&local->sockets.lock);
}
struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
@@ -122,6 +117,11 @@ 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;
+
return kref_put(&local->ref, local_release);
}
@@ -465,46 +465,107 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu)
sock->recv_ack_n = (sock->recv_n - 1) % 16;
}
+static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local *local,
+ u8 ssap)
+{
+ struct sock *sk;
+ struct nfc_llcp_sock *llcp_sock;
+ struct hlist_node *node;
+
+ read_lock(&local->connecting_sockets.lock);
+
+ sk_for_each(sk, node, &local->connecting_sockets.head) {
+ llcp_sock = nfc_llcp_sock(sk);
+
+ if (llcp_sock->ssap == ssap)
+ goto out;
+ }
+
+ llcp_sock = NULL;
+
+out:
+ read_unlock(&local->connecting_sockets.lock);
+
+ sock_hold(&llcp_sock->sk);
+
+ return llcp_sock;
+}
+
static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
u8 ssap, u8 dsap)
{
- struct nfc_llcp_sock *sock, *llcp_sock, *n;
+ 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;
- mutex_lock(&local->socket_lock);
- sock = local->sockets[ssap];
- if (sock == NULL) {
- mutex_unlock(&local->socket_lock);
- return NULL;
- }
+ read_lock(&local->sockets.lock);
+
+ llcp_sock = NULL;
- pr_debug("root dsap %d (%d)\n", sock->dsap, dsap);
+ sk_for_each(sk, node, &local->sockets.head) {
+ llcp_sock = nfc_llcp_sock(sk);
- if (sock->dsap == dsap) {
- sock_hold(&sock->sk);
- mutex_unlock(&local->socket_lock);
- return sock;
+ if (llcp_sock->ssap == ssap &&
+ llcp_sock->dsap == dsap)
+ break;
}
- list_for_each_entry_safe(llcp_sock, n, &sock->list, list) {
- pr_debug("llcp_sock %p sk %p dsap %d\n", llcp_sock,
- &llcp_sock->sk, llcp_sock->dsap);
- if (llcp_sock->dsap == dsap) {
- sock_hold(&llcp_sock->sk);
- mutex_unlock(&local->socket_lock);
- return llcp_sock;
- }
+ 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;
}
- pr_err("Could not find socket for %d %d\n", ssap, dsap);
+ read_unlock(&local->sockets.lock);
- mutex_unlock(&local->socket_lock);
+ if (llcp_sock == NULL)
+ return NULL;
- return NULL;
+ sock_hold(&llcp_sock->sk);
+
+ return llcp_sock;
}
static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock)
@@ -540,7 +601,7 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
{
struct sock *new_sk, *parent;
struct nfc_llcp_sock *sock, *new_sock;
- u8 dsap, ssap, bound_sap, reason;
+ u8 dsap, ssap, reason;
dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb);
@@ -551,24 +612,11 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
skb->len - LLCP_HEADER_SIZE);
if (dsap != LLCP_SAP_SDP) {
- bound_sap = dsap;
-
- mutex_lock(&local->socket_lock);
- sock = local->sockets[dsap];
- if (sock == NULL) {
- mutex_unlock(&local->socket_lock);
+ sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
+ if (sock == NULL || sock->sk.sk_state != LLCP_LISTEN) {
reason = LLCP_DM_NOBOUND;
goto fail;
}
-
- sock_hold(&sock->sk);
- mutex_unlock(&local->socket_lock);
-
- lock_sock(&sock->sk);
-
- if (sock->dsap == LLCP_SAP_SDP &&
- sock->sk.sk_state == LLCP_LISTEN)
- goto enqueue;
} else {
u8 *sn;
size_t sn_len;
@@ -581,40 +629,15 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
pr_debug("Service name length %zu\n", sn_len);
- mutex_lock(&local->socket_lock);
- for (bound_sap = 0; bound_sap < LLCP_LOCAL_SAP_OFFSET;
- bound_sap++) {
- sock = local->sockets[bound_sap];
- if (sock == NULL)
- continue;
-
- if (sock->service_name == NULL ||
- sock->service_name_len == 0)
- continue;
-
- if (sock->service_name_len != sn_len)
- continue;
-
- if (sock->dsap == LLCP_SAP_SDP &&
- sock->sk.sk_state == LLCP_LISTEN &&
- !memcmp(sn, sock->service_name, sn_len)) {
- pr_debug("Found service name at SAP %d\n",
- bound_sap);
- sock_hold(&sock->sk);
- mutex_unlock(&local->socket_lock);
-
- lock_sock(&sock->sk);
-
- goto enqueue;
- }
+ sock = nfc_llcp_sock_get_sn(local, sn, sn_len);
+ if (sock == NULL) {
+ reason = LLCP_DM_NOBOUND;
+ goto fail;
}
- mutex_unlock(&local->socket_lock);
}
- reason = LLCP_DM_NOBOUND;
- goto fail;
+ lock_sock(&sock->sk);
-enqueue:
parent = &sock->sk;
if (sk_acceptq_is_full(parent)) {
@@ -636,13 +659,13 @@ enqueue:
new_sock->dev = local->dev;
new_sock->local = nfc_llcp_local_get(local);
new_sock->nfc_protocol = sock->nfc_protocol;
- new_sock->ssap = bound_sap;
+ new_sock->ssap = sock->ssap;
new_sock->dsap = ssap;
new_sock->parent = parent;
pr_debug("new sock %p sk %p\n", new_sock, &new_sock->sk);
- list_add_tail(&new_sock->list, &sock->list);
+ nfc_llcp_sock_link(&local->sockets, new_sk);
nfc_llcp_accept_enqueue(&sock->sk, new_sk);
@@ -813,11 +836,7 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb);
- llcp_sock = nfc_llcp_sock_get(local, dsap, ssap);
-
- if (llcp_sock == NULL)
- llcp_sock = nfc_llcp_sock_get(local, dsap, LLCP_SAP_SDP);
-
+ llcp_sock = nfc_llcp_connecting_sock_get(local, dsap);
if (llcp_sock == NULL) {
pr_err("Invalid CC\n");
nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN);
@@ -825,9 +844,13 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
return;
}
- llcp_sock->dsap = ssap;
sk = &llcp_sock->sk;
+ /* Unlink from connecting and link to the client array */
+ nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
+ nfc_llcp_sock_link(&local->sockets, sk);
+ llcp_sock->dsap = ssap;
+
nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
skb->len - LLCP_HEADER_SIZE);
@@ -967,7 +990,6 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
INIT_LIST_HEAD(&local->list);
kref_init(&local->ref);
mutex_init(&local->sdp_lock);
- mutex_init(&local->socket_lock);
init_timer(&local->link_timer);
local->link_timer.data = (unsigned long) local;
local->link_timer.function = nfc_llcp_symm_timer;
@@ -1007,6 +1029,9 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
goto err_rx_wq;
}
+ local->sockets.lock = __RW_LOCK_UNLOCKED(local->sockets.lock);
+ local->connecting_sockets.lock = __RW_LOCK_UNLOCKED(local->connecting_sockets.lock);
+
nfc_llcp_build_gb(local);
local->remote_miu = LLCP_DEFAULT_MIU;
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h
index bc61955..7053304 100644
--- a/net/nfc/llcp/llcp.h
+++ b/net/nfc/llcp/llcp.h
@@ -40,6 +40,11 @@ enum llcp_state {
struct nfc_llcp_sock;
+struct llcp_sock_list {
+ struct hlist_head head;
+ rwlock_t lock;
+};
+
struct nfc_llcp_local {
struct list_head list;
struct nfc_dev *dev;
@@ -47,7 +52,6 @@ struct nfc_llcp_local {
struct kref ref;
struct mutex sdp_lock;
- struct mutex socket_lock;
struct timer_list link_timer;
struct sk_buff_head tx_queue;
@@ -82,12 +86,12 @@ struct nfc_llcp_local {
u8 remote_rw;
/* sockets array */
- struct nfc_llcp_sock *sockets[LLCP_MAX_SAP];
+ struct llcp_sock_list sockets;
+ struct llcp_sock_list connecting_sockets;
};
struct nfc_llcp_sock {
struct sock sk;
- struct list_head list;
struct nfc_dev *dev;
struct nfc_llcp_local *local;
u32 target_idx;
@@ -166,6 +170,8 @@ struct nfc_llcp_sock {
#define LLCP_DM_REJ 0x03
+void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s);
+void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s);
struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local);
int nfc_llcp_local_put(struct nfc_llcp_local *local);
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index 9ac397b..8a60b53 100644
--- a/net/nfc/llcp/sock.c
+++ b/net/nfc/llcp/sock.c
@@ -124,7 +124,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
if (llcp_sock->ssap == LLCP_MAX_SAP)
goto put_dev;
- local->sockets[llcp_sock->ssap] = llcp_sock;
+ nfc_llcp_sock_link(&local->sockets, sk);
pr_debug("Socket bound to SAP %d\n", llcp_sock->ssap);
@@ -379,15 +379,6 @@ static int llcp_sock_release(struct socket *sock)
goto out;
}
- mutex_lock(&local->socket_lock);
-
- if (llcp_sock == local->sockets[llcp_sock->ssap])
- local->sockets[llcp_sock->ssap] = NULL;
- else
- list_del_init(&llcp_sock->list);
-
- mutex_unlock(&local->socket_lock);
-
lock_sock(sk);
/* Send a DISC */
@@ -412,14 +403,12 @@ static int llcp_sock_release(struct socket *sock)
}
}
- /* Freeing the SAP */
- if ((sk->sk_state == LLCP_CONNECTED
- && llcp_sock->ssap > LLCP_LOCAL_SAP_OFFSET) ||
- sk->sk_state == LLCP_BOUND || sk->sk_state == LLCP_LISTEN)
- nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
+ nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap);
release_sock(sk);
+ nfc_llcp_sock_unlink(&local->sockets, sk);
+
out:
sock_orphan(sk);
sock_put(sk);
@@ -505,21 +494,26 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
llcp_sock->service_name_len,
GFP_KERNEL);
- local->sockets[llcp_sock->ssap] = llcp_sock;
+ nfc_llcp_sock_link(&local->connecting_sockets, sk);
ret = nfc_llcp_send_connect(llcp_sock);
if (ret)
- goto put_dev;
+ goto sock_unlink;
ret = sock_wait_state(sk, LLCP_CONNECTED,
sock_sndtimeo(sk, flags & O_NONBLOCK));
if (ret)
- goto put_dev;
+ goto sock_unlink;
release_sock(sk);
return 0;
+sock_unlink:
+ nfc_llcp_put_ssap(local, llcp_sock->ssap);
+
+ nfc_llcp_sock_unlink(&local->connecting_sockets, sk);
+
put_dev:
nfc_put_device(dev);
@@ -690,7 +684,6 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
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);
- INIT_LIST_HEAD(&llcp_sock->list);
INIT_LIST_HEAD(&llcp_sock->accept_queue);
if (sock != NULL)
@@ -708,7 +701,6 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
skb_queue_purge(&sock->tx_backlog_queue);
list_del_init(&sock->accept_queue);
- list_del_init(&sock->list);
sock->parent = NULL;
--
1.7.9.1
Those define the ATR_RES response timeout after which the pn533 considers the
target to be mute.
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 2a7e4e8..d976344 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -104,8 +104,14 @@ struct pn533_fw_version {
};
/* PN533_CMD_RF_CONFIGURATION */
+#define PN533_CFGITEM_TIMING 0x02
#define PN533_CFGITEM_MAX_RETRIES 0x05
+#define PN533_CONFIG_TIMING_102 0xb
+#define PN533_CONFIG_TIMING_204 0xc
+#define PN533_CONFIG_TIMING_409 0xd
+#define PN533_CONFIG_TIMING_819 0xe
+
#define PN533_CONFIG_MAX_RETRIES_NO_RETRY 0x00
#define PN533_CONFIG_MAX_RETRIES_ENDLESS 0xFF
@@ -115,6 +121,12 @@ struct pn533_config_max_retries {
u8 mx_rty_passive_act;
} __packed;
+struct pn533_config_timing {
+ u8 rfu;
+ u8 atr_res_timeout;
+ u8 dep_timeout;
+} __packed;
+
/* PN533_CMD_IN_LIST_PASSIVE_TARGET */
/* felica commands opcode */
@@ -2004,6 +2016,7 @@ static int pn533_probe(struct usb_interface *interface,
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;
@@ -2115,6 +2128,18 @@ static int pn533_probe(struct usb_interface *interface,
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");
+ goto unregister_nfc_dev;
+ }
+
return 0;
unregister_nfc_dev:
--
1.7.9.1
When receiving an I or RR frame telling us that some of the pending queues
were not received, we should requeue them before the currently pending ones.
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/llcp.c | 86 ++++++++++++++++++++++++++++++++------------------
1 files changed, 55 insertions(+), 31 deletions(-)
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index b694313..0fc60da 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -411,28 +411,6 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
local->remote_gb_len - 3);
}
-static void nfc_llcp_tx_work(struct work_struct *work)
-{
- struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
- tx_work);
- struct sk_buff *skb;
-
- skb = skb_dequeue(&local->tx_queue);
- if (skb != NULL) {
- pr_debug("Sending pending skb\n");
- print_hex_dump(KERN_DEBUG, "LLCP Tx: ", DUMP_PREFIX_OFFSET,
- 16, 1, skb->data, skb->len, true);
-
- nfc_data_exchange(local->dev, local->target_idx,
- skb, nfc_llcp_recv, local);
- } else {
- nfc_llcp_send_symm(local->dev);
- }
-
- mod_timer(&local->link_timer,
- jiffies + msecs_to_jiffies(local->remote_lto));
-}
-
static u8 nfc_llcp_dsap(struct sk_buff *pdu)
{
return (pdu->data[0] & 0xfc) >> 2;
@@ -465,6 +443,45 @@ static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu)
sock->recv_ack_n = (sock->recv_n - 1) % 16;
}
+static void nfc_llcp_tx_work(struct work_struct *work)
+{
+ struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
+ tx_work);
+ struct sk_buff *skb;
+ struct sock *sk;
+ struct nfc_llcp_sock *llcp_sock;
+
+ skb = skb_dequeue(&local->tx_queue);
+ if (skb != NULL) {
+ sk = skb->sk;
+ llcp_sock = nfc_llcp_sock(sk);
+ if (llcp_sock != NULL) {
+ int ret;
+
+ pr_debug("Sending pending skb\n");
+ print_hex_dump(KERN_DEBUG, "LLCP Tx: ",
+ DUMP_PREFIX_OFFSET, 16, 1,
+ skb->data, skb->len, true);
+
+ ret = nfc_data_exchange(local->dev, local->target_idx,
+ skb, nfc_llcp_recv, local);
+
+ if (!ret && nfc_llcp_ptype(skb) == LLCP_PDU_I) {
+ skb = skb_get(skb);
+ skb_queue_tail(&llcp_sock->tx_pending_queue,
+ skb);
+ }
+ } else {
+ nfc_llcp_send_symm(local->dev);
+ }
+ } else {
+ nfc_llcp_send_symm(local->dev);
+ }
+
+ mod_timer(&local->link_timer,
+ jiffies + msecs_to_jiffies(2 * local->remote_lto));
+}
+
static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local *local,
u8 ssap)
{
@@ -705,7 +722,7 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
/* Try to queue some I frames for transmission */
while (sock->remote_ready &&
skb_queue_len(&sock->tx_pending_queue) < sock->rw) {
- struct sk_buff *pdu, *pending_pdu;
+ struct sk_buff *pdu;
pdu = skb_dequeue(&sock->tx_queue);
if (pdu == NULL)
@@ -714,10 +731,7 @@ int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
/* Update N(S)/N(R) */
nfc_llcp_set_nrns(sock, pdu);
- pending_pdu = skb_clone(pdu, GFP_KERNEL);
-
skb_queue_tail(&local->tx_queue, pdu);
- skb_queue_tail(&sock->tx_pending_queue, pending_pdu);
nr_frames++;
}
@@ -774,11 +788,21 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
llcp_sock->send_ack_n = nr;
- skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp)
- if (nfc_llcp_ns(s) <= nr) {
- skb_unlink(s, &llcp_sock->tx_pending_queue);
- kfree_skb(s);
- }
+ /* Remove and free all skbs until ns == nr */
+ skb_queue_walk_safe(&llcp_sock->tx_pending_queue, s, tmp) {
+ skb_unlink(s, &llcp_sock->tx_pending_queue);
+ kfree_skb(s);
+
+ if (nfc_llcp_ns(s) == nr)
+ break;
+ }
+
+ /* Re-queue the remaining skbs for transmission */
+ skb_queue_reverse_walk_safe(&llcp_sock->tx_pending_queue,
+ s, tmp) {
+ skb_unlink(s, &llcp_sock->tx_pending_queue);
+ skb_queue_head(&local->tx_queue, s);
+ }
}
if (ptype == LLCP_PDU_RR)
--
1.7.9.1
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 39 +++++++++++++++++++++++++++++----------
drivers/nfc/pn544_hci.c | 10 ++++++----
include/linux/nfc.h | 4 ++++
include/net/nfc/hci.h | 3 ++-
include/net/nfc/nfc.h | 3 ++-
include/net/nfc/shdlc.h | 3 ++-
net/nfc/core.c | 10 +++++-----
net/nfc/hci/core.c | 5 +++--
net/nfc/hci/shdlc.c | 6 ++++--
net/nfc/nci/core.c | 7 ++++---
net/nfc/netlink.c | 19 +++++++++++++++----
net/nfc/nfc.h | 2 +-
12 files changed, 77 insertions(+), 34 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 19110f0..38a523c 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -1078,27 +1078,23 @@ stop_poll:
return 0;
}
-static int pn533_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
+static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols)
+{
+ return 0;
+}
+
+static int pn533_start_im_poll(struct nfc_dev *nfc_dev, u32 protocols)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct pn533_poll_modulations *start_mod;
int rc;
- nfc_dev_dbg(&dev->interface->dev, "%s - protocols=0x%x", __func__,
- protocols);
-
if (dev->poll_mod_count) {
nfc_dev_err(&dev->interface->dev, "Polling operation already"
" active");
return -EBUSY;
}
- if (dev->tgt_active_prot) {
- nfc_dev_err(&dev->interface->dev, "Cannot poll with a target"
- " already activated");
- return -EBUSY;
- }
-
pn533_poll_create_mod_list(dev, protocols);
if (!dev->poll_mod_count) {
@@ -1135,6 +1131,29 @@ error:
return rc;
}
+static int pn533_start_poll(struct nfc_dev *nfc_dev,
+ u32 im_protocols, u32 tm_protocols)
+{
+ struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+
+ nfc_dev_dbg(&dev->interface->dev,
+ "%s: im protocols 0x%x tm protocols 0x%x",
+ __func__, im_protocols, tm_protocols);
+
+ if (dev->tgt_active_prot) {
+ nfc_dev_err(&dev->interface->dev,
+ "Cannot poll with a target already activated");
+ return -EBUSY;
+ }
+
+ if (!tm_protocols)
+ return pn533_start_im_poll(nfc_dev, im_protocols);
+ else if (!im_protocols)
+ return pn533_init_target(nfc_dev, tm_protocols);
+ else
+ return -EINVAL;
+}
+
static void pn533_stop_poll(struct nfc_dev *nfc_dev)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c
index 281f18c..457eac3 100644
--- a/drivers/nfc/pn544_hci.c
+++ b/drivers/nfc/pn544_hci.c
@@ -576,7 +576,8 @@ static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb)
return pn544_hci_i2c_write(client, skb->data, skb->len);
}
-static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
+static int pn544_hci_start_poll(struct nfc_shdlc *shdlc,
+ u32 im_protocols, u32 tm_protocols)
{
struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
u8 phases = 0;
@@ -584,7 +585,8 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
u8 duration[2];
u8 activated;
- pr_info(DRIVER_DESC ": %s protocols = %d\n", __func__, protocols);
+ pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
+ __func__, im_protocols, tm_protocols);
r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
NFC_HCI_EVT_END_OPERATION, NULL, 0);
@@ -604,10 +606,10 @@ static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
if (r < 0)
return r;
- if (protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
+ if (im_protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
NFC_PROTO_JEWEL_MASK))
phases |= 1; /* Type A */
- if (protocols & NFC_PROTO_FELICA_MASK) {
+ if (im_protocols & NFC_PROTO_FELICA_MASK) {
phases |= (1 << 2); /* Type F 212 */
phases |= (1 << 3); /* Type F 424 */
}
diff --git a/include/linux/nfc.h b/include/linux/nfc.h
index 0ae9b58..5487158 100644
--- a/include/linux/nfc.h
+++ b/include/linux/nfc.h
@@ -94,6 +94,8 @@ enum nfc_commands {
* @NFC_ATTR_TARGET_SENSF_RES: NFC-F targets extra information, max 18 bytes
* @NFC_ATTR_COMM_MODE: Passive or active mode
* @NFC_ATTR_RF_MODE: Initiator or target
+ * @NFC_ATTR_IM_PROTOCOLS: Initiator mode protocols to poll for
+ * @NFC_ATTR_TM_PROTOCOLS: Target mode protocols to listen for
*/
enum nfc_attrs {
NFC_ATTR_UNSPEC,
@@ -109,6 +111,8 @@ enum nfc_attrs {
NFC_ATTR_COMM_MODE,
NFC_ATTR_RF_MODE,
NFC_ATTR_DEVICE_POWERED,
+ NFC_ATTR_IM_PROTOCOLS,
+ NFC_ATTR_TM_PROTOCOLS,
/* private: internal use only */
__NFC_ATTR_AFTER_LAST
};
diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h
index 4467c94..e30e6a8 100644
--- a/include/net/nfc/hci.h
+++ b/include/net/nfc/hci.h
@@ -31,7 +31,8 @@ struct nfc_hci_ops {
void (*close) (struct nfc_hci_dev *hdev);
int (*hci_ready) (struct nfc_hci_dev *hdev);
int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
- int (*start_poll) (struct nfc_hci_dev *hdev, u32 protocols);
+ int (*start_poll) (struct nfc_hci_dev *hdev,
+ u32 im_protocols, u32 tm_protocols);
int (*target_from_gate) (struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index 3116f92..97aa0e8 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -53,7 +53,8 @@ struct nfc_target;
struct nfc_ops {
int (*dev_up)(struct nfc_dev *dev);
int (*dev_down)(struct nfc_dev *dev);
- int (*start_poll)(struct nfc_dev *dev, u32 protocols);
+ int (*start_poll)(struct nfc_dev *dev,
+ u32 im_protocols, u32 tm_protocols);
void (*stop_poll)(struct nfc_dev *dev);
int (*dep_link_up)(struct nfc_dev *dev, struct nfc_target *target,
u8 comm_mode, u8 *gb, size_t gb_len);
diff --git a/include/net/nfc/shdlc.h b/include/net/nfc/shdlc.h
index ab06afd..35e930d 100644
--- a/include/net/nfc/shdlc.h
+++ b/include/net/nfc/shdlc.h
@@ -27,7 +27,8 @@ struct nfc_shdlc_ops {
void (*close) (struct nfc_shdlc *shdlc);
int (*hci_ready) (struct nfc_shdlc *shdlc);
int (*xmit) (struct nfc_shdlc *shdlc, struct sk_buff *skb);
- int (*start_poll) (struct nfc_shdlc *shdlc, u32 protocols);
+ int (*start_poll) (struct nfc_shdlc *shdlc,
+ u32 im_protocols, u32 tm_protocols);
int (*target_from_gate) (struct nfc_shdlc *shdlc, u8 gate,
struct nfc_target *target);
int (*complete_target_discovered) (struct nfc_shdlc *shdlc, u8 gate,
diff --git a/net/nfc/core.c b/net/nfc/core.c
index f5a43f7..c83717b 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -121,14 +121,14 @@ error:
* The device remains polling for targets until a target is found or
* the nfc_stop_poll function is called.
*/
-int nfc_start_poll(struct nfc_dev *dev, u32 protocols)
+int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
{
int rc;
- pr_debug("dev_name=%s protocols=0x%x\n",
- dev_name(&dev->dev), protocols);
+ pr_debug("dev_name %s initiator protocols 0x%x target protocols 0x%x\n",
+ dev_name(&dev->dev), im_protocols, tm_protocols);
- if (!protocols)
+ if (!im_protocols && !tm_protocols)
return -EINVAL;
device_lock(&dev->dev);
@@ -143,7 +143,7 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols)
goto error;
}
- rc = dev->ops->start_poll(dev, protocols);
+ rc = dev->ops->start_poll(dev, im_protocols, tm_protocols);
if (!rc)
dev->polling = true;
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index e1a640d..281f3a3 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -481,12 +481,13 @@ static int hci_dev_down(struct nfc_dev *nfc_dev)
return 0;
}
-static int hci_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
+static int hci_start_poll(struct nfc_dev *nfc_dev,
+ u32 im_protocols, u32 tm_protocols)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
if (hdev->ops->start_poll)
- return hdev->ops->start_poll(hdev, protocols);
+ return hdev->ops->start_poll(hdev, im_protocols, tm_protocols);
else
return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c
index 5665dc6..6b836e6 100644
--- a/net/nfc/hci/shdlc.c
+++ b/net/nfc/hci/shdlc.c
@@ -765,14 +765,16 @@ static int nfc_shdlc_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
return 0;
}
-static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev, u32 protocols)
+static int nfc_shdlc_start_poll(struct nfc_hci_dev *hdev,
+ u32 im_protocols, u32 tm_protocols)
{
struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
pr_debug("\n");
if (shdlc->ops->start_poll)
- return shdlc->ops->start_poll(shdlc, protocols);
+ return shdlc->ops->start_poll(shdlc,
+ im_protocols, tm_protocols);
return 0;
}
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index d560e6f..0f71898 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -387,7 +387,8 @@ static int nci_dev_down(struct nfc_dev *nfc_dev)
return nci_close_device(ndev);
}
-static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
+static int nci_start_poll(struct nfc_dev *nfc_dev,
+ __u32 im_protocols, __u32 tm_protocols)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
int rc;
@@ -413,11 +414,11 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
return -EBUSY;
}
- rc = nci_request(ndev, nci_rf_discover_req, protocols,
+ rc = nci_request(ndev, nci_rf_discover_req, im_protocols,
msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
if (!rc)
- ndev->poll_prots = protocols;
+ ndev->poll_prots = im_protocols;
return rc;
}
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 581d419..a18fd56 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -49,6 +49,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
[NFC_ATTR_COMM_MODE] = { .type = NLA_U8 },
[NFC_ATTR_RF_MODE] = { .type = NLA_U8 },
[NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
+ [NFC_ATTR_IM_PROTOCOLS] = { .type = NLA_U32 },
+ [NFC_ATTR_TM_PROTOCOLS] = { .type = NLA_U32 },
};
static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
@@ -519,16 +521,25 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
struct nfc_dev *dev;
int rc;
u32 idx;
- u32 protocols;
+ u32 im_protocols = 0, tm_protocols = 0;
pr_debug("Poll start\n");
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
- !info->attrs[NFC_ATTR_PROTOCOLS])
+ ((!info->attrs[NFC_ATTR_IM_PROTOCOLS] &&
+ !info->attrs[NFC_ATTR_PROTOCOLS]) &&
+ !info->attrs[NFC_ATTR_TM_PROTOCOLS]))
return -EINVAL;
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
- protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
+
+ if (info->attrs[NFC_ATTR_TM_PROTOCOLS])
+ tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_TM_PROTOCOLS]);
+ else if (info->attrs[NFC_ATTR_PROTOCOLS])
+ tm_protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
+
+ if (info->attrs[NFC_ATTR_IM_PROTOCOLS])
+ im_protocols = nla_get_u32(info->attrs[NFC_ATTR_IM_PROTOCOLS]);
dev = nfc_get_device(idx);
if (!dev)
@@ -536,7 +547,7 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
mutex_lock(&dev->genl_data.genl_data_mutex);
- rc = nfc_start_poll(dev, protocols);
+ rc = nfc_start_poll(dev, im_protocols, tm_protocols);
if (!rc)
dev->genl_data.poll_req_pid = info->snd_pid;
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index 3dd4232..7d9708f 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -158,7 +158,7 @@ int nfc_dev_up(struct nfc_dev *dev);
int nfc_dev_down(struct nfc_dev *dev);
-int nfc_start_poll(struct nfc_dev *dev, u32 protocols);
+int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols);
int nfc_stop_poll(struct nfc_dev *dev);
--
1.7.9.1
After going through all the modulations, the pn533 driver spends 2
seconds listening for targets.
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 287 ++++++++++++++++++++++++++++----------------------
1 files changed, 161 insertions(+), 126 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 6e4b228..c9ba96c 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -45,6 +45,9 @@ static const struct usb_device_id pn533_table[] = {
};
MODULE_DEVICE_TABLE(usb, pn533_table);
+/* How much time we spend listening for initiators */
+#define PN533_LISTEN_TIME 2
+
/* frame definitions */
#define PN533_FRAME_TAIL_SIZE 2
#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
@@ -163,6 +166,7 @@ enum {
PN533_POLL_MOD_424KBPS_FELICA,
PN533_POLL_MOD_106KBPS_JEWEL,
PN533_POLL_MOD_847KBPS_B,
+ PN533_LISTEN_MOD,
__PN533_POLL_MOD_AFTER_LAST,
};
@@ -230,6 +234,9 @@ const struct pn533_poll_modulations poll_mod[] = {
},
.len = 3,
},
+ [PN533_LISTEN_MOD] = {
+ .len = 0,
+ },
};
/* PN533_CMD_IN_ATR */
@@ -312,10 +319,13 @@ struct pn533 {
struct workqueue_struct *wq;
struct work_struct cmd_work;
+ struct work_struct poll_work;
struct work_struct mi_work;
struct work_struct tg_work;
+ struct timer_list listen_timer;
struct pn533_frame *wq_in_frame;
int wq_in_error;
+ int cancel_listen;
pn533_cmd_complete_t cmd_complete;
void *cmd_complete_arg;
@@ -326,6 +336,10 @@ struct pn533 {
u8 poll_mod_count;
u8 poll_mod_curr;
u32 poll_protocols;
+ u32 listen_protocols;
+
+ u8 *gb;
+ size_t gb_len;
u8 tgt_available_prots;
u8 tgt_active_prot;
@@ -1006,6 +1020,11 @@ static int pn533_target_found(struct pn533 *dev,
return 0;
}
+static inline void pn533_poll_next_mod(struct pn533 *dev)
+{
+ dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
+}
+
static void pn533_poll_reset_mod_list(struct pn533 *dev)
{
dev->poll_mod_count = 0;
@@ -1018,107 +1037,52 @@ static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index)
dev->poll_mod_count++;
}
-static void pn533_poll_create_mod_list(struct pn533 *dev, u32 protocols)
+static void pn533_poll_create_mod_list(struct pn533 *dev,
+ u32 im_protocols, u32 tm_protocols)
{
pn533_poll_reset_mod_list(dev);
- if (protocols & NFC_PROTO_MIFARE_MASK
- || protocols & NFC_PROTO_ISO14443_MASK
- || protocols & NFC_PROTO_NFC_DEP_MASK)
+ if (im_protocols & NFC_PROTO_MIFARE_MASK
+ || im_protocols & NFC_PROTO_ISO14443_MASK
+ || im_protocols & NFC_PROTO_NFC_DEP_MASK)
pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A);
- if (protocols & NFC_PROTO_FELICA_MASK
- || protocols & NFC_PROTO_NFC_DEP_MASK) {
+ if (im_protocols & NFC_PROTO_FELICA_MASK
+ || im_protocols & NFC_PROTO_NFC_DEP_MASK) {
pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA);
pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA);
}
- if (protocols & NFC_PROTO_JEWEL_MASK)
+ if (im_protocols & NFC_PROTO_JEWEL_MASK)
pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL);
- if (protocols & NFC_PROTO_ISO14443_MASK)
+ if (im_protocols & NFC_PROTO_ISO14443_MASK)
pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B);
-}
-
-static void pn533_start_poll_frame(struct pn533_frame *frame,
- struct pn533_poll_modulations *mod)
-{
-
- pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
- memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
- frame->datalen += mod->len;
-
- pn533_tx_frame_finish(frame);
+ if (tm_protocols)
+ pn533_poll_add_mod(dev, PN533_LISTEN_MOD);
}
static int pn533_start_poll_complete(struct pn533 *dev, void *arg,
- u8 *params, int params_len)
+ u8 *params, int params_len)
{
struct pn533_poll_response *resp;
- struct pn533_poll_modulations *next_mod;
int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- if (params_len == -ENOENT) {
- nfc_dev_dbg(&dev->interface->dev, "Polling operation has been"
- " stopped");
- goto stop_poll;
- }
-
- if (params_len < 0) {
- nfc_dev_err(&dev->interface->dev, "Error %d when running poll",
- params_len);
- goto stop_poll;
- }
-
resp = (struct pn533_poll_response *) params;
if (resp->nbtg) {
rc = pn533_target_found(dev, resp, params_len);
/* We must stop the poll after a valid target found */
- if (rc == 0)
- goto stop_poll;
-
- if (rc != -EAGAIN)
- nfc_dev_err(&dev->interface->dev, "The target found is"
- " not valid - continuing to poll");
- }
-
- dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
-
- next_mod = dev->poll_mod_active[dev->poll_mod_curr];
-
- nfc_dev_dbg(&dev->interface->dev, "Polling next modulation (0x%x)",
- dev->poll_mod_curr);
-
- pn533_start_poll_frame(dev->out_frame, next_mod);
-
- /* Don't need to down the semaphore again */
- rc = __pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
- dev->in_maxlen, pn533_start_poll_complete,
- NULL, GFP_ATOMIC);
-
- if (rc == -EPERM) {
- nfc_dev_dbg(&dev->interface->dev, "Cannot poll next modulation"
- " because poll has been stopped");
- goto stop_poll;
- }
-
- if (rc) {
- nfc_dev_err(&dev->interface->dev, "Error %d when trying to poll"
- " next modulation", rc);
- goto stop_poll;
+ if (rc == 0) {
+ pn533_poll_reset_mod_list(dev);
+ return 0;
+ }
}
- /* Inform caller function to do not up the semaphore */
- return -EINPROGRESS;
-
-stop_poll:
- pn533_poll_reset_mod_list(dev);
- dev->poll_protocols = 0;
- return 0;
+ return -EAGAIN;
}
static int pn533_init_target_frame(struct pn533_frame *frame,
@@ -1286,83 +1250,136 @@ static int pn533_init_target_complete(struct pn533 *dev, void *arg,
return 0;
}
-static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols)
+static void pn533_listen_mode_timer(unsigned long data)
{
- struct pn533 *dev = nfc_get_drvdata(nfc_dev);
- u8 *gb;
- size_t gb_len;
+ struct pn533 *dev = (struct pn533 *) data;
+
+ nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout");
+
+ /* An ack will cancel the last issued command (poll) */
+ pn533_send_ack(dev, GFP_ATOMIC);
+
+ dev->cancel_listen = 1;
+
+ up(&dev->cmd_lock);
+
+ pn533_poll_next_mod(dev);
+
+ queue_work(dev->wq, &dev->poll_work);
+}
+
+static int pn533_poll_complete(struct pn533 *dev, void *arg,
+ u8 *params, int params_len)
+{
+ struct pn533_poll_modulations *cur_mod;
int rc;
- pn533_poll_reset_mod_list(dev);
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- gb = nfc_get_local_general_bytes(nfc_dev, &gb_len);
- if (gb == NULL)
- return -ENOMEM;
+ if (params_len == -ENOENT) {
+ if (dev->poll_mod_count != 0)
+ return 0;
- rc = pn533_init_target_frame(dev->out_frame, gb, gb_len);
- if (rc < 0)
- return rc;
+ nfc_dev_err(&dev->interface->dev,
+ "Polling operation has been stopped");
- rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
- dev->in_maxlen,
- pn533_init_target_complete,
- NULL, GFP_KERNEL);
+ goto stop_poll;
+ }
- if (rc)
+ if (params_len < 0) {
nfc_dev_err(&dev->interface->dev,
- "Error %d when trying to initiate as a target", rc);
+ "Error %d when running poll", params_len);
- dev->poll_mod_count++;
+ goto stop_poll;
+ }
- return rc;
+ cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+ if (cur_mod->len == 0) {
+ del_timer(&dev->listen_timer);
+
+ return pn533_init_target_complete(dev, arg, params, params_len);
+ } else {
+ rc = pn533_start_poll_complete(dev, arg, params, params_len);
+ if (!rc)
+ return rc;
+ }
+
+ pn533_poll_next_mod(dev);
+
+ queue_work(dev->wq, &dev->poll_work);
+
+ return 0;
+
+stop_poll:
+ pn533_poll_reset_mod_list(dev);
+ dev->poll_protocols = 0;
+ return 0;
}
-static int pn533_start_im_poll(struct nfc_dev *nfc_dev, u32 protocols)
+static void pn533_build_poll_frame(struct pn533 *dev,
+ struct pn533_frame *frame,
+ struct pn533_poll_modulations *mod)
{
- struct pn533 *dev = nfc_get_drvdata(nfc_dev);
- struct pn533_poll_modulations *start_mod;
- int rc;
+ nfc_dev_dbg(&dev->interface->dev, "mod len %d\n", mod->len);
- if (dev->poll_mod_count) {
- nfc_dev_err(&dev->interface->dev, "Polling operation already"
- " active");
- return -EBUSY;
- }
+ if (mod->len == 0) {
+ /* Listen mode */
+ pn533_init_target_frame(frame, dev->gb, dev->gb_len);
+ } else {
+ /* Polling mode */
+ pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
- pn533_poll_create_mod_list(dev, protocols);
+ memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
+ frame->datalen += mod->len;
- if (!dev->poll_mod_count) {
- nfc_dev_err(&dev->interface->dev, "No valid protocols"
- " specified");
- rc = -EINVAL;
- goto error;
+ pn533_tx_frame_finish(frame);
}
+}
- nfc_dev_dbg(&dev->interface->dev, "It will poll %d modulations types",
- dev->poll_mod_count);
+static int pn533_send_poll_frame(struct pn533 *dev)
+{
+ struct pn533_poll_modulations *cur_mod;
+ int rc;
- dev->poll_mod_curr = 0;
- start_mod = dev->poll_mod_active[dev->poll_mod_curr];
+ cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
- pn533_start_poll_frame(dev->out_frame, start_mod);
+ pn533_build_poll_frame(dev, dev->out_frame, cur_mod);
rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
- dev->in_maxlen, pn533_start_poll_complete,
+ dev->in_maxlen, pn533_poll_complete,
NULL, GFP_KERNEL);
+ if (rc)
+ nfc_dev_err(&dev->interface->dev, "Polling loop error %d", rc);
- if (rc) {
- nfc_dev_err(&dev->interface->dev, "Error %d when trying to"
- " start poll", rc);
- goto error;
+ return rc;
+}
+
+static void pn533_wq_poll(struct work_struct *work)
+{
+ struct pn533 *dev = container_of(work, struct pn533, poll_work);
+ struct pn533_poll_modulations *cur_mod;
+ int rc;
+
+ cur_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+ nfc_dev_dbg(&dev->interface->dev,
+ "%s cancel_listen %d modulation len %d",
+ __func__, dev->cancel_listen, cur_mod->len);
+
+ if (dev->cancel_listen == 1) {
+ dev->cancel_listen = 0;
+ usb_kill_urb(dev->in_urb);
}
- dev->poll_protocols = protocols;
+ rc = pn533_send_poll_frame(dev);
+ if (rc)
+ return;
- return 0;
+ if (cur_mod->len == 0 && dev->poll_mod_count > 1)
+ mod_timer(&dev->listen_timer, jiffies + PN533_LISTEN_TIME * HZ);
-error:
- pn533_poll_reset_mod_list(dev);
- return rc;
+ return;
}
static int pn533_start_poll(struct nfc_dev *nfc_dev,
@@ -1380,13 +1397,18 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev,
return -EBUSY;
}
- if (im_protocols)
- return pn533_start_im_poll(nfc_dev, im_protocols);
+ if (tm_protocols) {
+ dev->gb = nfc_get_local_general_bytes(nfc_dev, &dev->gb_len);
+ if (dev->gb == NULL)
+ tm_protocols = 0;
+ }
- if (tm_protocols)
- return pn533_init_target(nfc_dev, tm_protocols);
+ dev->poll_mod_curr = 0;
+ pn533_poll_create_mod_list(dev, im_protocols, tm_protocols);
+ dev->poll_protocols = im_protocols;
+ dev->listen_protocols = tm_protocols;
- return -EINVAL;
+ return pn533_send_poll_frame(dev);
}
static void pn533_stop_poll(struct nfc_dev *nfc_dev)
@@ -1395,6 +1417,8 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+ del_timer(&dev->listen_timer);
+
if (!dev->poll_mod_count) {
nfc_dev_dbg(&dev->interface->dev, "Polling operation was not"
" running");
@@ -1676,6 +1700,10 @@ out:
static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
{
+ struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+
+ pn533_poll_reset_mod_list(dev);
+
pn533_deactivate_target(nfc_dev, 0);
return 0;
@@ -2110,12 +2138,17 @@ static int pn533_probe(struct usb_interface *interface,
INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete);
INIT_WORK(&dev->mi_work, pn533_wq_mi_recv);
INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data);
+ INIT_WORK(&dev->poll_work, pn533_wq_poll);
dev->wq = alloc_workqueue("pn533",
WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
1);
if (dev->wq == NULL)
goto error;
+ init_timer(&dev->listen_timer);
+ dev->listen_timer.data = (unsigned long) dev;
+ dev->listen_timer.function = pn533_listen_mode_timer;
+
skb_queue_head_init(&dev->resp_q);
usb_set_intfdata(interface, dev);
@@ -2212,6 +2245,8 @@ static void pn533_disconnect(struct usb_interface *interface)
skb_queue_purge(&dev->resp_q);
+ del_timer(&dev->listen_timer);
+
kfree(dev->in_frame);
usb_free_urb(dev->in_urb);
kfree(dev->out_frame);
--
1.7.9.1
Even in target mode we need to let the driver know that we want to
bring the DEP link down.
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/core.c | 5 -----
1 files changed, 0 insertions(+), 5 deletions(-)
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 6a3799e..4177bb5 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -268,11 +268,6 @@ int nfc_dep_link_down(struct nfc_dev *dev)
goto error;
}
- if (dev->rf_mode == NFC_RF_TARGET) {
- rc = -EOPNOTSUPP;
- goto error;
- }
-
rc = dev->ops->dep_link_down(dev);
if (!rc) {
dev->dep_link_up = false;
--
1.7.9.1
LLCP sockets point to their local LLCP service, so they need to take a
reference on it.
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/llcp.c | 46 +++++++++++++++++++++++++++++++---------------
net/nfc/llcp/llcp.h | 4 ++++
net/nfc/llcp/sock.c | 14 +++++---------
3 files changed, 40 insertions(+), 24 deletions(-)
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 42994fa..0f6dd3a 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -59,8 +59,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
release_sock(sk);
sock_orphan(sk);
-
- s->local = NULL;
}
parent_sk = &parent->sk;
@@ -83,8 +81,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
release_sock(accept_sk);
sock_orphan(accept_sk);
-
- lsk->local = NULL;
}
}
@@ -96,13 +92,39 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
release_sock(parent_sk);
sock_orphan(parent_sk);
-
- parent->local = NULL;
}
mutex_unlock(&local->socket_lock);
}
+struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
+{
+ kref_get(&local->ref);
+
+ return local;
+}
+
+static void local_release(struct kref *ref)
+{
+ struct nfc_llcp_local *local;
+
+ local = container_of(ref, struct nfc_llcp_local, ref);
+
+ list_del(&local->list);
+ nfc_llcp_socket_release(local);
+ del_timer_sync(&local->link_timer);
+ skb_queue_purge(&local->tx_queue);
+ destroy_workqueue(local->tx_wq);
+ destroy_workqueue(local->rx_wq);
+ kfree_skb(local->rx_pending);
+ kfree(local);
+}
+
+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);
@@ -612,7 +634,7 @@ enqueue:
new_sock = nfc_llcp_sock(new_sk);
new_sock->dev = local->dev;
- new_sock->local = local;
+ new_sock->local = nfc_llcp_local_get(local);
new_sock->nfc_protocol = sock->nfc_protocol;
new_sock->ssap = bound_sap;
new_sock->dsap = ssap;
@@ -943,6 +965,7 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
local->dev = ndev;
INIT_LIST_HEAD(&local->list);
+ kref_init(&local->ref);
mutex_init(&local->sdp_lock);
mutex_init(&local->socket_lock);
init_timer(&local->link_timer);
@@ -1015,14 +1038,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev)
return;
}
- list_del(&local->list);
- nfc_llcp_socket_release(local);
- del_timer_sync(&local->link_timer);
- skb_queue_purge(&local->tx_queue);
- destroy_workqueue(local->tx_wq);
- destroy_workqueue(local->rx_wq);
- kfree_skb(local->rx_pending);
- kfree(local);
+ nfc_llcp_local_put(local);
}
int __init nfc_llcp_init(void)
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h
index 50680ce..bc61955 100644
--- a/net/nfc/llcp/llcp.h
+++ b/net/nfc/llcp/llcp.h
@@ -44,6 +44,8 @@ struct nfc_llcp_local {
struct list_head list;
struct nfc_dev *dev;
+ struct kref ref;
+
struct mutex sdp_lock;
struct mutex socket_lock;
@@ -165,6 +167,8 @@ struct nfc_llcp_sock {
struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
+struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local);
+int nfc_llcp_local_put(struct nfc_llcp_local *local);
u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
struct nfc_llcp_sock *sock);
u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local);
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index 3f339b1..9ac397b 100644
--- a/net/nfc/llcp/sock.c
+++ b/net/nfc/llcp/sock.c
@@ -111,7 +111,7 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
}
llcp_sock->dev = dev;
- llcp_sock->local = local;
+ llcp_sock->local = nfc_llcp_local_get(local);
llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
llcp_sock->service_name_len = min_t(unsigned int,
llcp_addr.service_name_len,
@@ -487,7 +487,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
}
llcp_sock->dev = dev;
- llcp_sock->local = local;
+ llcp_sock->local = nfc_llcp_local_get(local);
llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
if (llcp_sock->ssap == LLCP_SAP_MAX) {
ret = -ENOMEM;
@@ -701,8 +701,6 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
{
- struct nfc_llcp_local *local = sock->local;
-
kfree(sock->service_name);
skb_queue_purge(&sock->tx_queue);
@@ -710,13 +708,11 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
skb_queue_purge(&sock->tx_backlog_queue);
list_del_init(&sock->accept_queue);
-
- if (local != NULL && sock == local->sockets[sock->ssap])
- local->sockets[sock->ssap] = NULL;
- else
- list_del_init(&sock->list);
+ list_del_init(&sock->list);
sock->parent = NULL;
+
+ nfc_llcp_local_put(sock->local);
}
static int llcp_sock_create(struct net *net, struct socket *sock,
--
1.7.9.1
We only want to support p2p target mode for now, no host card emulation.
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 104 insertions(+), 5 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 38a523c..605a08a 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -74,6 +74,8 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_CMD_IN_RELEASE 0x52
#define PN533_CMD_IN_JUMP_FOR_DEP 0x56
+#define PN533_CMD_TG_INIT_AS_TARGET 0x8c
+
#define PN533_CMD_RESPONSE(cmd) (cmd + 1)
/* PN533 Return codes */
@@ -253,6 +255,25 @@ struct pn533_cmd_jump_dep_response {
u8 gt[];
} __packed;
+
+/* PN533_TG_INIT_AS_TARGET */
+#define PN533_INIT_TARGET_PASSIVE 0x1
+#define PN533_INIT_TARGET_DEP 0x2
+
+struct pn533_cmd_init_target {
+ u8 mode;
+ u8 mifare[6];
+ u8 felica[18];
+ u8 nfcid3[10];
+ u8 gb_len;
+ u8 gb[];
+} __packed;
+
+struct pn533_cmd_init_target_response {
+ u8 mode;
+ u8 cmd[];
+} __packed;
+
struct pn533 {
struct usb_device *udev;
struct usb_interface *interface;
@@ -1078,11 +1099,88 @@ stop_poll:
return 0;
}
-static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols)
+static int pn533_init_target_frame(struct pn533_frame *frame,
+ u8 *gb, size_t gb_len)
{
+ struct pn533_cmd_init_target *cmd;
+ size_t cmd_len;
+
+ cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1;
+ cmd = kzalloc(cmd_len, GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ pn533_tx_frame_init(frame, PN533_CMD_TG_INIT_AS_TARGET);
+
+ /* DEP support only */
+ cmd->mode |= PN533_INIT_TARGET_DEP;
+ get_random_bytes(cmd->nfcid3, 10);
+ cmd->gb_len = gb_len;
+ memcpy(cmd->gb, gb, gb_len);
+ /* Len Tk */
+ cmd->gb[gb_len] = 0;
+
+ memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len);
+ frame->datalen += cmd_len;
+
+ pn533_tx_frame_finish(frame);
+
return 0;
}
+static int pn533_init_target_complete(struct pn533 *dev, void *arg,
+ u8 *params, int params_len)
+{
+ struct pn533_cmd_init_target_response *resp;
+
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+ if (params_len < 0) {
+ nfc_dev_err(&dev->interface->dev,
+ "Error %d when starting as a target",
+ params_len);
+
+ return params_len;
+ }
+
+ resp = (struct pn533_cmd_init_target_response *) params;
+
+ nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x\n", resp->mode);
+
+ return 0;
+}
+
+static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols)
+{
+ struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+ u8 *gb;
+ size_t gb_len;
+ int rc;
+
+ pn533_poll_reset_mod_list(dev);
+
+ gb = nfc_get_local_general_bytes(nfc_dev, &gb_len);
+ if (gb == NULL)
+ return -ENOMEM;
+
+ rc = pn533_init_target_frame(dev->out_frame, gb, gb_len);
+ if (rc < 0)
+ return rc;
+
+ rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
+ dev->in_maxlen,
+ pn533_init_target_complete,
+ NULL, GFP_KERNEL);
+
+ if (rc)
+ nfc_dev_err(&dev->interface->dev,
+ "Error %d when trying to initiate as a target", rc);
+
+ dev->poll_mod_count++;
+
+ return rc;
+}
+
static int pn533_start_im_poll(struct nfc_dev *nfc_dev, u32 protocols)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
@@ -1146,12 +1244,13 @@ static int pn533_start_poll(struct nfc_dev *nfc_dev,
return -EBUSY;
}
- if (!tm_protocols)
+ if (im_protocols)
return pn533_start_im_poll(nfc_dev, im_protocols);
- else if (!im_protocols)
+
+ if (tm_protocols)
return pn533_init_target(nfc_dev, tm_protocols);
- else
- return -EINVAL;
+
+ return -EINVAL;
}
static void pn533_stop_poll(struct nfc_dev *nfc_dev)
--
1.7.9.1
This one needs to be called as soon as we are activated as a target, for
the pn533 to receive the first SYMM and keep the LLCP link alive.
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 80 insertions(+), 5 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index fd94c6f..6a506e2 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -75,6 +75,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_CMD_IN_JUMP_FOR_DEP 0x56
#define PN533_CMD_TG_INIT_AS_TARGET 0x8c
+#define PN533_CMD_TG_GET_DATA 0x86
#define PN533_CMD_RESPONSE(cmd) (cmd + 1)
@@ -83,6 +84,9 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
#define PN533_CMD_MI_MASK 0x40
#define PN533_CMD_RET_SUCCESS 0x00
+/* PN533 status codes */
+#define PN533_STATUS_TARGET_RELEASED 0x29
+
struct pn533;
typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg,
@@ -296,6 +300,7 @@ struct pn533 {
struct workqueue_struct *wq;
struct work_struct cmd_work;
struct work_struct mi_work;
+ struct work_struct tg_work;
struct pn533_frame *wq_in_frame;
int wq_in_error;
@@ -1132,6 +1137,68 @@ static int pn533_init_target_frame(struct pn533_frame *frame,
return 0;
}
+#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
+#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
+static int pn533_tm_get_data_complete(struct pn533 *dev, void *arg,
+ u8 *params, int params_len)
+{
+ struct sk_buff *skb_resp = arg;
+ struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
+
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+ if (params_len < 0) {
+ nfc_dev_err(&dev->interface->dev,
+ "Error %d when starting as a target",
+ params_len);
+
+ return params_len;
+ }
+
+ if (params_len > 0 && params[0] != 0) {
+ nfc_tm_deactivated(dev->nfc_dev);
+
+ kfree_skb(skb_resp);
+ return 0;
+ }
+
+ skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
+ skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
+ skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
+
+ return nfc_tm_data_received(dev->nfc_dev, skb_resp);
+}
+
+static void pn533_wq_tg_get_data(struct work_struct *work)
+{
+ struct pn533 *dev = container_of(work, struct pn533, tg_work);
+ struct pn533_frame *in_frame;
+ struct sk_buff *skb_resp;
+ size_t skb_resp_len;
+
+ nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+ skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
+ PN533_CMD_DATAEXCH_DATA_MAXLEN +
+ PN533_FRAME_TAIL_SIZE;
+
+ skb_resp = nfc_alloc_recv_skb(skb_resp_len, GFP_KERNEL);
+ if (!skb_resp)
+ return;
+
+ in_frame = (struct pn533_frame *)skb_resp->data;
+
+ pn533_tx_frame_init(dev->out_frame, PN533_CMD_TG_GET_DATA);
+ pn533_tx_frame_finish(dev->out_frame);
+
+ pn533_send_cmd_frame_async(dev, dev->out_frame, in_frame,
+ skb_resp_len,
+ pn533_tm_get_data_complete,
+ skb_resp, GFP_KERNEL);
+
+ return;
+}
+
#define ATR_REQ_GB_OFFSET 17
static int pn533_init_target_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
@@ -1139,6 +1206,7 @@ static int pn533_init_target_complete(struct pn533 *dev, void *arg,
struct pn533_cmd_init_target_response *resp;
u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
size_t gb_len;
+ int rc;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
@@ -1169,8 +1237,17 @@ static int pn533_init_target_complete(struct pn533 *dev, void *arg,
gb = resp->cmd + ATR_REQ_GB_OFFSET;
gb_len = params_len - (ATR_REQ_GB_OFFSET + 1);
- return nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
- comm_mode, gb, gb_len);
+ rc = nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
+ comm_mode, gb, gb_len);
+ if (rc < 0) {
+ nfc_dev_err(&dev->interface->dev,
+ "Error when signaling target activation");
+ return rc;
+ }
+
+ queue_work(dev->wq, &dev->tg_work);
+
+ return 0;
}
static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols)
@@ -1553,9 +1630,6 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
return 0;
}
-#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
-#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
-
static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
{
int payload_len = skb->len;
@@ -1920,6 +1994,7 @@ static int pn533_probe(struct usb_interface *interface,
INIT_WORK(&dev->cmd_work, pn533_wq_cmd_complete);
INIT_WORK(&dev->mi_work, pn533_wq_mi_recv);
+ INIT_WORK(&dev->tg_work, pn533_wq_tg_get_data);
dev->wq = alloc_workqueue("pn533",
WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
1);
--
1.7.9.1
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index b97e3c8..58c1641 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -329,7 +329,7 @@ struct pn533 {
pn533_cmd_complete_t cmd_complete;
void *cmd_complete_arg;
- struct semaphore cmd_lock;
+ struct mutex cmd_lock;
u8 cmd;
struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
@@ -462,7 +462,7 @@ static void pn533_wq_cmd_complete(struct work_struct *work)
PN533_FRAME_CMD_PARAMS_LEN(in_frame));
if (rc != -EINPROGRESS)
- up(&dev->cmd_lock);
+ mutex_unlock(&dev->cmd_lock);
}
static void pn533_recv_response(struct urb *urb)
@@ -640,7 +640,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
- if (down_trylock(&dev->cmd_lock))
+ if (!mutex_trylock(&dev->cmd_lock))
return -EBUSY;
rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
@@ -650,7 +650,7 @@ static int pn533_send_cmd_frame_async(struct pn533 *dev,
return 0;
error:
- up(&dev->cmd_lock);
+ mutex_unlock(&dev->cmd_lock);
return rc;
}
@@ -1261,7 +1261,7 @@ static void pn533_listen_mode_timer(unsigned long data)
dev->cancel_listen = 1;
- up(&dev->cmd_lock);
+ mutex_unlock(&dev->cmd_lock);
pn533_poll_next_mod(dev);
@@ -2054,7 +2054,7 @@ error_cmd:
kfree(arg);
- up(&dev->cmd_lock);
+ mutex_unlock(&dev->cmd_lock);
}
static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
@@ -2114,7 +2114,7 @@ static int pn533_probe(struct usb_interface *interface,
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
- sema_init(&dev->cmd_lock, 1);
+ mutex_init(&dev->cmd_lock);
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
--
1.7.9.1
Userspace gets a netlink event upon target mode activation.
The LLCP layer is also signaled when we get an ATR_REQ in order to get
the remote general bytes.
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 27 +++++++++++++++++++-
include/linux/nfc.h | 7 +++++
include/net/nfc/nfc.h | 4 +++
net/nfc/core.c | 35 +++++++++++++++++++++++++++
net/nfc/netlink.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++
net/nfc/nfc.h | 3 ++
6 files changed, 136 insertions(+), 2 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 605a08a..c6b9bc5 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -260,6 +260,10 @@ struct pn533_cmd_jump_dep_response {
#define PN533_INIT_TARGET_PASSIVE 0x1
#define PN533_INIT_TARGET_DEP 0x2
+#define PN533_INIT_TARGET_RESP_FRAME_MASK 0x3
+#define PN533_INIT_TARGET_RESP_ACTIVE 0x1
+#define PN533_INIT_TARGET_RESP_DEP 0x4
+
struct pn533_cmd_init_target {
u8 mode;
u8 mifare[6];
@@ -1128,10 +1132,13 @@ static int pn533_init_target_frame(struct pn533_frame *frame,
return 0;
}
+#define ATR_REQ_GB_OFFSET 17
static int pn533_init_target_complete(struct pn533 *dev, void *arg,
u8 *params, int params_len)
{
struct pn533_cmd_init_target_response *resp;
+ u8 frame, comm_mode = NFC_COMM_PASSIVE, *gb;
+ size_t gb_len;
nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
@@ -1143,11 +1150,27 @@ static int pn533_init_target_complete(struct pn533 *dev, void *arg,
return params_len;
}
+ if (params_len < ATR_REQ_GB_OFFSET + 1)
+ return -EINVAL;
+
resp = (struct pn533_cmd_init_target_response *) params;
- nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x\n", resp->mode);
+ nfc_dev_dbg(&dev->interface->dev, "Target mode 0x%x param len %d\n",
+ resp->mode, params_len);
- return 0;
+ frame = resp->mode & PN533_INIT_TARGET_RESP_FRAME_MASK;
+ if (frame == PN533_INIT_TARGET_RESP_ACTIVE)
+ comm_mode = NFC_COMM_ACTIVE;
+
+ /* Again, only DEP */
+ if ((resp->mode & PN533_INIT_TARGET_RESP_DEP) == 0)
+ return -EOPNOTSUPP;
+
+ gb = resp->cmd + ATR_REQ_GB_OFFSET;
+ gb_len = params_len - (ATR_REQ_GB_OFFSET + 1);
+
+ return nfc_tm_activated(dev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
+ comm_mode, gb, gb_len);
}
static int pn533_init_target(struct nfc_dev *nfc_dev, u32 protocols)
diff --git a/include/linux/nfc.h b/include/linux/nfc.h
index 5487158..d124e92 100644
--- a/include/linux/nfc.h
+++ b/include/linux/nfc.h
@@ -56,6 +56,10 @@
* %NFC_ATTR_PROTOCOLS)
* @NFC_EVENT_DEVICE_REMOVED: event emitted when a device is removed
* (it sends %NFC_ATTR_DEVICE_INDEX)
+ * @NFC_EVENT_TM_ACTIVATED: event emitted when the adapter is activated in
+ * target mode.
+ * @NFC_EVENT_DEVICE_DEACTIVATED: event emitted when the adapter is deactivated
+ * from target mode.
*/
enum nfc_commands {
NFC_CMD_UNSPEC,
@@ -71,6 +75,8 @@ enum nfc_commands {
NFC_EVENT_DEVICE_ADDED,
NFC_EVENT_DEVICE_REMOVED,
NFC_EVENT_TARGET_LOST,
+ NFC_EVENT_TM_ACTIVATED,
+ NFC_EVENT_TM_DEACTIVATED,
/* private: internal use only */
__NFC_CMD_AFTER_LAST
};
@@ -122,6 +128,7 @@ enum nfc_attrs {
#define NFC_NFCID1_MAXSIZE 10
#define NFC_SENSB_RES_MAXSIZE 12
#define NFC_SENSF_RES_MAXSIZE 18
+#define NFC_GB_MAXSIZE 48
/* NFC protocols */
#define NFC_PROTO_JEWEL 1
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index 97aa0e8..41573b4b 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -198,4 +198,8 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx);
int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
u8 comm_mode, u8 rf_mode);
+int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
+ u8 *gb, size_t gb_len);
+int nfc_tm_deactivated(struct nfc_dev *dev);
+
#endif /* __NET_NFC_H */
diff --git a/net/nfc/core.c b/net/nfc/core.c
index c83717b..17f1474 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -455,6 +455,41 @@ u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len)
}
EXPORT_SYMBOL(nfc_get_local_general_bytes);
+int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
+ u8 *gb, size_t gb_len)
+{
+ int rc;
+
+ device_lock(&dev->dev);
+
+ dev->polling = false;
+
+ if (gb != NULL) {
+ rc = nfc_set_remote_general_bytes(dev, gb, gb_len);
+ if (rc < 0)
+ goto out;
+ }
+
+ if (protocol == NFC_PROTO_NFC_DEP_MASK)
+ nfc_dep_link_is_up(dev, 0, comm_mode, NFC_RF_TARGET);
+
+ rc = nfc_genl_tm_activated(dev, protocol);
+
+out:
+ device_unlock(&dev->dev);
+
+ return rc;
+}
+EXPORT_SYMBOL(nfc_tm_activated);
+
+int nfc_tm_deactivated(struct nfc_dev *dev)
+{
+ dev->dep_link_up = false;
+
+ return nfc_genl_tm_deactivated(dev);
+}
+EXPORT_SYMBOL(nfc_tm_deactivated);
+
/**
* nfc_alloc_send_skb - allocate a skb for data exchange responses
*
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index a18fd56..21eaa9b 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -221,6 +221,68 @@ free_msg:
return -EMSGSIZE;
}
+int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+ NFC_EVENT_TM_ACTIVATED);
+ if (!hdr)
+ goto free_msg;
+
+ if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+ goto nla_put_failure;
+ if (nla_put_u32(msg, NFC_ATTR_TM_PROTOCOLS, protocol))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+
+ return 0;
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+free_msg:
+ nlmsg_free(msg);
+ return -EMSGSIZE;
+}
+
+int nfc_genl_tm_deactivated(struct nfc_dev *dev)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+ NFC_EVENT_TM_DEACTIVATED);
+ if (!hdr)
+ goto free_msg;
+
+ if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+
+ return 0;
+
+nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+free_msg:
+ nlmsg_free(msg);
+ return -EMSGSIZE;
+}
+
int nfc_genl_device_added(struct nfc_dev *dev)
{
struct sk_buff *msg;
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index 7d9708f..cd9fcbe 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -128,6 +128,9 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
u8 comm_mode, u8 rf_mode);
int nfc_genl_dep_link_down_event(struct nfc_dev *dev);
+int nfc_genl_tm_activated(struct nfc_dev *dev, u32 protocol);
+int nfc_genl_tm_deactivated(struct nfc_dev *dev);
+
struct nfc_dev *nfc_get_device(unsigned int idx);
static inline void nfc_put_device(struct nfc_dev *dev)
--
1.7.9.1
Signed-off-by: Samuel Ortiz <[email protected]>
---
include/linux/nfc.h | 1 +
include/net/nfc/nfc.h | 2 +-
net/nfc/core.c | 14 ++++++++++----
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/include/linux/nfc.h b/include/linux/nfc.h
index d124e92..f4e6dd9 100644
--- a/include/linux/nfc.h
+++ b/include/linux/nfc.h
@@ -146,6 +146,7 @@ enum nfc_attrs {
/* NFC RF modes */
#define NFC_RF_INITIATOR 0
#define NFC_RF_TARGET 1
+#define NFC_RF_NONE 2
/* NFC protocols masks used in bitsets */
#define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL)
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index 41573b4b..a6a7b49 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -100,10 +100,10 @@ struct nfc_dev {
int targets_generation;
struct device dev;
bool dev_up;
+ u8 rf_mode;
bool polling;
struct nfc_target *active_target;
bool dep_link_up;
- u32 dep_rf_mode;
struct nfc_genl_data genl_data;
u32 supported_protocols;
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 17f1474..722a0c7 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -144,8 +144,10 @@ int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
}
rc = dev->ops->start_poll(dev, im_protocols, tm_protocols);
- if (!rc)
+ if (!rc) {
dev->polling = true;
+ dev->rf_mode = NFC_RF_NONE;
+ }
error:
device_unlock(&dev->dev);
@@ -235,8 +237,10 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
}
rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len);
- if (!rc)
+ if (!rc) {
dev->active_target = target;
+ dev->rf_mode = NFC_RF_INITIATOR;
+ }
error:
device_unlock(&dev->dev);
@@ -264,7 +268,7 @@ int nfc_dep_link_down(struct nfc_dev *dev)
goto error;
}
- if (dev->dep_rf_mode == NFC_RF_TARGET) {
+ if (dev->rf_mode == NFC_RF_TARGET) {
rc = -EOPNOTSUPP;
goto error;
}
@@ -286,7 +290,6 @@ int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
u8 comm_mode, u8 rf_mode)
{
dev->dep_link_up = true;
- dev->dep_rf_mode = rf_mode;
nfc_llcp_mac_is_up(dev, target_idx, comm_mode, rf_mode);
@@ -330,6 +333,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
rc = dev->ops->activate_target(dev, target, protocol);
if (!rc) {
dev->active_target = target;
+ dev->rf_mode = NFC_RF_INITIATOR;
if (dev->ops->check_presence)
mod_timer(&dev->check_pres_timer, jiffies +
@@ -470,6 +474,8 @@ int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
goto out;
}
+ dev->rf_mode = NFC_RF_TARGET;
+
if (protocol == NFC_PROTO_NFC_DEP_MASK)
nfc_dep_link_is_up(dev, 0, comm_mode, NFC_RF_TARGET);
--
1.7.9.1
The mask is 0x7ff and not 0x7f and the return value is an u16.
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/commands.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c
index 850e5cf..b982b5b 100644
--- a/net/nfc/llcp/commands.c
+++ b/net/nfc/llcp/commands.c
@@ -51,7 +51,7 @@ static u8 llcp_tlv8(u8 *tlv, u8 type)
return tlv[2];
}
-static u8 llcp_tlv16(u8 *tlv, u8 type)
+static u16 llcp_tlv16(u8 *tlv, u8 type)
{
if (tlv[0] != type || tlv[1] != llcp_tlv_length[tlv[0]])
return 0;
@@ -67,7 +67,7 @@ static u8 llcp_tlv_version(u8 *tlv)
static u16 llcp_tlv_miux(u8 *tlv)
{
- return llcp_tlv16(tlv, LLCP_TLV_MIUX) & 0x7f;
+ return llcp_tlv16(tlv, LLCP_TLV_MIUX) & 0x7ff;
}
static u16 llcp_tlv_wks(u8 *tlv)
--
1.7.9.1
The MIU extension value can be received during the PAX or during the
connection establishment process. It's definitely a connection related value
rather than a link one.
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/commands.c | 7 +++++--
net/nfc/llcp/llcp.c | 1 +
net/nfc/llcp/llcp.h | 1 +
net/nfc/llcp/sock.c | 2 ++
4 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c
index eb51864..850e5cf 100644
--- a/net/nfc/llcp/commands.c
+++ b/net/nfc/llcp/commands.c
@@ -183,6 +183,9 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
pr_debug("type 0x%x length %d\n", type, length);
switch (type) {
+ case LLCP_TLV_MIUX:
+ sock->miu = llcp_tlv_miux(tlv) + 128;
+ break;
case LLCP_TLV_RW:
sock->rw = llcp_tlv_rw(tlv);
break;
@@ -197,7 +200,7 @@ int nfc_llcp_parse_connection_tlv(struct nfc_llcp_sock *sock,
tlv += length + 2;
}
- pr_debug("sock %p rw %d\n", sock, sock->rw);
+ pr_debug("sock %p rw %d miu %d\n", sock, sock->rw, sock->miu);
return 0;
}
@@ -505,7 +508,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
while (remaining_len > 0) {
- frag_len = min_t(size_t, local->remote_miu, remaining_len);
+ frag_len = min_t(size_t, sock->miu, remaining_len);
pr_debug("Fragment %zd bytes remaining %zd",
frag_len, remaining_len);
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index d3efc5b..5f7aa3f 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -655,6 +655,7 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
new_sock = nfc_llcp_sock(new_sk);
new_sock->dev = local->dev;
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;
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h
index add03e7..7286c86 100644
--- a/net/nfc/llcp/llcp.h
+++ b/net/nfc/llcp/llcp.h
@@ -102,6 +102,7 @@ struct nfc_llcp_sock {
char *service_name;
size_t service_name_len;
u8 rw;
+ u16 miu;
/* Link variables */
u8 send_n;
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index aab077e..30e3cc7 100644
--- a/net/nfc/llcp/sock.c
+++ b/net/nfc/llcp/sock.c
@@ -477,6 +477,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
llcp_sock->dev = dev;
llcp_sock->local = nfc_llcp_local_get(local);
+ llcp_sock->miu = llcp_sock->local->remote_miu;
llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
if (llcp_sock->ssap == LLCP_SAP_MAX) {
ret = -ENOMEM;
@@ -679,6 +680,7 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
llcp_sock->ssap = 0;
llcp_sock->dsap = LLCP_SAP_SDP;
llcp_sock->rw = LLCP_DEFAULT_RW;
+ llcp_sock->miu = LLCP_DEFAULT_MIU;
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;
--
1.7.9.1
This routine will be called by drivers whenever they receive data in target
mode. This should be unexpected events and as such should be handled by a
standalone API (i.e. not as a callback pointer from an existing API).
Signed-off-by: Samuel Ortiz <[email protected]>
---
include/net/nfc/nfc.h | 1 +
net/nfc/core.c | 12 ++++++++++++
net/nfc/llcp/llcp.c | 15 +++++++++++++++
net/nfc/nfc.h | 7 +++++++
4 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index 45c4c97..180964b 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -202,5 +202,6 @@ int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
u8 *gb, size_t gb_len);
int nfc_tm_deactivated(struct nfc_dev *dev);
+int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb);
#endif /* __NET_NFC_H */
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 76c1e20..6a3799e 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -462,6 +462,18 @@ u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len)
}
EXPORT_SYMBOL(nfc_get_local_general_bytes);
+int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb)
+{
+ /* Only LLCP target mode for now */
+ if (dev->dep_link_up == false) {
+ kfree_skb(skb);
+ return -ENOLINK;
+ }
+
+ return nfc_llcp_data_received(dev, skb);
+}
+EXPORT_SYMBOL(nfc_tm_data_received);
+
int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode,
u8 *gb, size_t gb_len)
{
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 5f7aa3f..5705e6d 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -937,6 +937,21 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
return;
}
+int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb)
+{
+ struct nfc_llcp_local *local;
+
+ local = nfc_llcp_find_local(dev);
+ if (local == NULL)
+ return -ENODEV;
+
+ local->rx_pending = skb_get(skb);
+ del_timer(&local->link_timer);
+ queue_work(local->rx_wq, &local->rx_work);
+
+ return 0;
+}
+
void nfc_llcp_mac_is_down(struct nfc_dev *dev)
{
struct nfc_llcp_local *local;
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index cd9fcbe..c5e42b7 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -55,6 +55,7 @@ int nfc_llcp_register_device(struct nfc_dev *dev);
void nfc_llcp_unregister_device(struct nfc_dev *dev);
int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len);
u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len);
+int nfc_llcp_data_received(struct nfc_dev *dev, struct sk_buff *skb);
int __init nfc_llcp_init(void);
void nfc_llcp_exit(void);
@@ -90,6 +91,12 @@ static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *gb_len)
return NULL;
}
+static inline int nfc_llcp_data_received(struct nfc_dev *dev,
+ struct sk_buff *skb)
+{
+ return 0;
+}
+
static inline int nfc_llcp_init(void)
{
return 0;
--
1.7.9.1
Signed-off-by: Samuel Ortiz <[email protected]>
---
include/net/nfc/nfc.h | 1 +
net/nfc/core.c | 8 ++++++++
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index b7ca4a2..3116f92 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -188,6 +188,7 @@ struct sk_buff *nfc_alloc_recv_skb(unsigned int size, gfp_t gfp);
int nfc_set_remote_general_bytes(struct nfc_dev *dev,
u8 *gt, u8 gt_len);
+u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len);
int nfc_targets_found(struct nfc_dev *dev,
struct nfc_target *targets, int ntargets);
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 9f6ce01..f5a43f7 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -447,6 +447,14 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len)
}
EXPORT_SYMBOL(nfc_set_remote_general_bytes);
+u8 *nfc_get_local_general_bytes(struct nfc_dev *dev, size_t *gb_len)
+{
+ pr_debug("dev_name=%s\n", dev_name(&dev->dev));
+
+ return nfc_llcp_general_bytes(dev, gb_len);
+}
+EXPORT_SYMBOL(nfc_get_local_general_bytes);
+
/**
* nfc_alloc_send_skb - allocate a skb for data exchange responses
*
--
1.7.9.1
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/llcp.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 3fe68e1..5d503ee 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -111,6 +111,7 @@ static void local_release(struct kref *ref)
skb_queue_purge(&local->tx_queue);
destroy_workqueue(local->tx_wq);
destroy_workqueue(local->rx_wq);
+ destroy_workqueue(local->timeout_wq);
kfree_skb(local->rx_pending);
kfree(local);
}
--
1.7.9.1
Signed-off-by: Samuel Ortiz <[email protected]>
---
net/nfc/llcp/llcp.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 5705e6d..b694313 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -477,8 +477,10 @@ static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local
sk_for_each(sk, node, &local->connecting_sockets.head) {
llcp_sock = nfc_llcp_sock(sk);
- if (llcp_sock->ssap == ssap)
+ if (llcp_sock->ssap == ssap) {
+ sock_hold(&llcp_sock->sk);
goto out;
+ }
}
llcp_sock = NULL;
@@ -486,8 +488,6 @@ static struct nfc_llcp_sock *nfc_llcp_connecting_sock_get(struct nfc_llcp_local
out:
read_unlock(&local->connecting_sockets.lock);
- sock_hold(&llcp_sock->sk);
-
return llcp_sock;
}
--
1.7.9.1
Without those settings several devices will not activate pn533 as a target.
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 25 ++++++++++++++++++++++++-
1 files changed, 24 insertions(+), 1 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index 806ab3d..6e4b228 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -1126,6 +1126,13 @@ static int pn533_init_target_frame(struct pn533_frame *frame,
{
struct pn533_cmd_init_target *cmd;
size_t cmd_len;
+ u8 felica_params[18] = {0x1, 0xfe, /* DEP */
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* random */
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0xff, 0xff}; /* System code */
+ u8 mifare_params[6] = {0x1, 0x1, /* SENS_RES */
+ 0x0, 0x0, 0x0,
+ 0x40}; /* SEL_RES for DEP */
cmd_len = sizeof(struct pn533_cmd_init_target) + gb_len + 1;
cmd = kzalloc(cmd_len, GFP_KERNEL);
@@ -1136,17 +1143,33 @@ static int pn533_init_target_frame(struct pn533_frame *frame,
/* DEP support only */
cmd->mode |= PN533_INIT_TARGET_DEP;
- get_random_bytes(cmd->nfcid3, 10);
+
+ /* Felica params */
+ memcpy(cmd->felica, felica_params, 18);
+ get_random_bytes(cmd->felica + 2, 6);
+
+ /* NFCID3 */
+ memset(cmd->nfcid3, 0, 10);
+ memcpy(cmd->nfcid3, cmd->felica, 8);
+
+ /* MIFARE params */
+ memcpy(cmd->mifare, mifare_params, 6);
+
+ /* General bytes */
cmd->gb_len = gb_len;
memcpy(cmd->gb, gb, gb_len);
+
/* Len Tk */
cmd->gb[gb_len] = 0;
memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), cmd, cmd_len);
+
frame->datalen += cmd_len;
pn533_tx_frame_finish(frame);
+ kfree(cmd);
+
return 0;
}
--
1.7.9.1
Signed-off-by: Samuel Ortiz <[email protected]>
---
drivers/nfc/pn533.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index db40787..6b8a65c 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -1371,6 +1371,8 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
/* prevent pn533_start_poll_complete to issue a new poll meanwhile */
usb_kill_urb(dev->in_urb);
+
+ pn533_poll_reset_mod_list(dev);
}
static int pn533_activate_target_nfcdep(struct pn533 *dev)
--
1.7.9.1