summaryrefslogtreecommitdiffstats
path: root/net/nfc
diff options
context:
space:
mode:
Diffstat (limited to 'net/nfc')
-rw-r--r--net/nfc/af_nfc.c2
-rw-r--r--net/nfc/core.c55
-rw-r--r--net/nfc/llcp/commands.c163
-rw-r--r--net/nfc/llcp/llcp.c201
-rw-r--r--net/nfc/llcp/llcp.h12
-rw-r--r--net/nfc/llcp/sock.c120
-rw-r--r--net/nfc/nci/core.c209
-rw-r--r--net/nfc/nci/data.c32
-rw-r--r--net/nfc/nci/ntf.c360
-rw-r--r--net/nfc/nci/rsp.c41
-rw-r--r--net/nfc/netlink.c73
-rw-r--r--net/nfc/nfc.h18
-rw-r--r--net/nfc/rawsock.c28
13 files changed, 926 insertions, 388 deletions
diff --git a/net/nfc/af_nfc.c b/net/nfc/af_nfc.c
index da67756..9d68441 100644
--- a/net/nfc/af_nfc.c
+++ b/net/nfc/af_nfc.c
@@ -30,7 +30,7 @@ static DEFINE_RWLOCK(proto_tab_lock);
static const struct nfc_protocol *proto_tab[NFC_SOCKPROTO_MAX];
static int nfc_sock_create(struct net *net, struct socket *sock, int proto,
- int kern)
+ int kern)
{
int rc = -EPROTONOSUPPORT;
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 3ddf6e6..295d129 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -181,13 +181,13 @@ error:
return rc;
}
-int nfc_dep_link_up(struct nfc_dev *dev, int target_index,
- u8 comm_mode, u8 rf_mode)
+int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
{
int rc = 0;
+ u8 *gb;
+ size_t gb_len;
- pr_debug("dev_name=%s comm:%d rf:%d\n",
- dev_name(&dev->dev), comm_mode, rf_mode);
+ pr_debug("dev_name=%s comm %d\n", dev_name(&dev->dev), comm_mode);
if (!dev->ops->dep_link_up)
return -EOPNOTSUPP;
@@ -204,7 +204,13 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index,
goto error;
}
- rc = dev->ops->dep_link_up(dev, target_index, comm_mode, rf_mode);
+ gb = nfc_llcp_general_bytes(dev, &gb_len);
+ if (gb_len > NFC_MAX_GT_LEN) {
+ rc = -EINVAL;
+ goto error;
+ }
+
+ rc = dev->ops->dep_link_up(dev, target_index, comm_mode, gb, gb_len);
error:
device_unlock(&dev->dev);
@@ -250,7 +256,7 @@ error:
}
int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
- u8 comm_mode, u8 rf_mode)
+ u8 comm_mode, u8 rf_mode)
{
dev->dep_link_up = true;
dev->dep_rf_mode = rf_mode;
@@ -330,10 +336,8 @@ error:
*
* The user must wait for the callback before calling this function again.
*/
-int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx,
- struct sk_buff *skb,
- data_exchange_cb_t cb,
- void *cb_context)
+int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
+ data_exchange_cb_t cb, void *cb_context)
{
int rc;
@@ -357,8 +361,7 @@ error:
int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len)
{
- pr_debug("dev_name=%s gb_len=%d\n",
- dev_name(&dev->dev), gb_len);
+ pr_debug("dev_name=%s gb_len=%d\n", dev_name(&dev->dev), gb_len);
if (gb_len > NFC_MAX_GT_LEN)
return -EINVAL;
@@ -367,12 +370,6 @@ 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, u8 *gt_len)
-{
- return nfc_llcp_general_bytes(dev, gt_len);
-}
-EXPORT_SYMBOL(nfc_get_local_general_bytes);
-
/**
* nfc_alloc_send_skb - allocate a skb for data exchange responses
*
@@ -380,8 +377,8 @@ EXPORT_SYMBOL(nfc_get_local_general_bytes);
* @gfp: gfp flags
*/
struct sk_buff *nfc_alloc_send_skb(struct nfc_dev *dev, struct sock *sk,
- unsigned int flags, unsigned int size,
- unsigned int *err)
+ unsigned int flags, unsigned int size,
+ unsigned int *err)
{
struct sk_buff *skb;
unsigned int total_size;
@@ -428,25 +425,20 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb);
* are found. After calling this function, the device driver must stop
* polling for targets.
*/
-int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
- int n_targets)
+int nfc_targets_found(struct nfc_dev *dev,
+ struct nfc_target *targets, int n_targets)
{
- int i;
-
pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets);
dev->polling = false;
- for (i = 0; i < n_targets; i++)
- targets[i].idx = dev->target_idx++;
-
spin_lock_bh(&dev->targets_lock);
dev->targets_generation++;
kfree(dev->targets);
dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target),
- GFP_ATOMIC);
+ GFP_ATOMIC);
if (!dev->targets) {
dev->n_targets = 0;
@@ -506,15 +498,14 @@ struct nfc_dev *nfc_get_device(unsigned idx)
* @supported_protocols: NFC protocols supported by the device
*/
struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
- u32 supported_protocols,
- int tx_headroom,
- int tx_tailroom)
+ u32 supported_protocols,
+ int tx_headroom, int tx_tailroom)
{
static atomic_t dev_no = ATOMIC_INIT(0);
struct nfc_dev *dev;
if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
- !ops->deactivate_target || !ops->data_exchange)
+ !ops->deactivate_target || !ops->data_exchange)
return NULL;
if (!supported_protocols)
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c
index 151f2ef..7b76eb7 100644
--- a/net/nfc/llcp/commands.c
+++ b/net/nfc/llcp/commands.c
@@ -118,7 +118,7 @@ u8 *nfc_llcp_build_tlv(u8 type, u8 *value, u8 value_length, u8 *tlv_length)
}
int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
- u8 *tlv_array, u16 tlv_array_len)
+ u8 *tlv_array, u16 tlv_array_len)
{
u8 *tlv = tlv_array, type, length, offset = 0;
@@ -152,6 +152,8 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
case LLCP_TLV_RW:
local->remote_rw = llcp_tlv_rw(tlv);
break;
+ case LLCP_TLV_SN:
+ break;
default:
pr_err("Invalid gt tlv value 0x%x\n", type);
break;
@@ -162,15 +164,15 @@ int nfc_llcp_parse_tlv(struct nfc_llcp_local *local,
}
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);
+ local->remote_version, local->remote_miu,
+ local->remote_lto, local->remote_opt,
+ local->remote_wks, local->remote_rw);
return 0;
}
static struct sk_buff *llcp_add_header(struct sk_buff *pdu,
- u8 dsap, u8 ssap, u8 ptype)
+ u8 dsap, u8 ssap, u8 ptype)
{
u8 header[2];
@@ -186,7 +188,8 @@ static struct sk_buff *llcp_add_header(struct sk_buff *pdu,
return pdu;
}
-static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv, u8 tlv_length)
+static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv,
+ u8 tlv_length)
{
/* XXX Add an skb length check */
@@ -199,7 +202,7 @@ static struct sk_buff *llcp_add_tlv(struct sk_buff *pdu, u8 *tlv, u8 tlv_length)
}
static struct sk_buff *llcp_allocate_pdu(struct nfc_llcp_sock *sock,
- u8 cmd, u16 size)
+ u8 cmd, u16 size)
{
struct sk_buff *skb;
int err;
@@ -208,7 +211,7 @@ static struct sk_buff *llcp_allocate_pdu(struct nfc_llcp_sock *sock,
return NULL;
skb = nfc_alloc_send_skb(sock->dev, &sock->sk, MSG_DONTWAIT,
- size + LLCP_HEADER_SIZE, &err);
+ size + LLCP_HEADER_SIZE, &err);
if (skb == NULL) {
pr_err("Could not allocate PDU\n");
return NULL;
@@ -276,7 +279,7 @@ int nfc_llcp_send_symm(struct nfc_dev *dev)
skb = llcp_add_header(skb, 0, 0, LLCP_PDU_SYMM);
return nfc_data_exchange(dev, local->target_idx, skb,
- nfc_llcp_recv, local);
+ nfc_llcp_recv, local);
}
int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
@@ -284,6 +287,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
struct nfc_llcp_local *local;
struct sk_buff *skb;
u8 *service_name_tlv = NULL, service_name_tlv_length;
+ u8 *miux_tlv = NULL, miux_tlv_length;
+ u8 *rw_tlv = NULL, rw_tlv_length, rw;
+ __be16 miux;
int err;
u16 size = 0;
@@ -295,12 +301,21 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
if (sock->service_name != NULL) {
service_name_tlv = nfc_llcp_build_tlv(LLCP_TLV_SN,
- sock->service_name,
- sock->service_name_len,
- &service_name_tlv_length);
+ sock->service_name,
+ sock->service_name_len,
+ &service_name_tlv_length);
size += service_name_tlv_length;
}
+ miux = cpu_to_be16(LLCP_MAX_MIUX);
+ miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
+ &miux_tlv_length);
+ size += miux_tlv_length;
+
+ rw = LLCP_MAX_RW;
+ rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
+ size += rw_tlv_length;
+
pr_debug("SKB size %d SN length %zu\n", size, sock->service_name_len);
skb = llcp_allocate_pdu(sock, LLCP_PDU_CONNECT, size);
@@ -311,7 +326,10 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
if (service_name_tlv != NULL)
skb = llcp_add_tlv(skb, service_name_tlv,
- service_name_tlv_length);
+ service_name_tlv_length);
+
+ skb = llcp_add_tlv(skb, miux_tlv, miux_tlv_length);
+ skb = llcp_add_tlv(skb, rw_tlv, rw_tlv_length);
skb_queue_tail(&local->tx_queue, skb);
@@ -321,6 +339,8 @@ error_tlv:
pr_err("error %d\n", err);
kfree(service_name_tlv);
+ kfree(miux_tlv);
+ kfree(rw_tlv);
return err;
}
@@ -329,6 +349,11 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
{
struct nfc_llcp_local *local;
struct sk_buff *skb;
+ u8 *miux_tlv = NULL, miux_tlv_length;
+ u8 *rw_tlv = NULL, rw_tlv_length, rw;
+ __be16 miux;
+ int err;
+ u16 size = 0;
pr_debug("Sending CC\n");
@@ -336,13 +361,35 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
if (local == NULL)
return -ENODEV;
- skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, 0);
- if (skb == NULL)
- return -ENOMEM;
+ miux = cpu_to_be16(LLCP_MAX_MIUX);
+ miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
+ &miux_tlv_length);
+ size += miux_tlv_length;
+
+ rw = LLCP_MAX_RW;
+ rw_tlv = nfc_llcp_build_tlv(LLCP_TLV_RW, &rw, 0, &rw_tlv_length);
+ size += rw_tlv_length;
+
+ skb = llcp_allocate_pdu(sock, LLCP_PDU_CC, size);
+ if (skb == NULL) {
+ err = -ENOMEM;
+ goto error_tlv;
+ }
+
+ skb = llcp_add_tlv(skb, miux_tlv, miux_tlv_length);
+ skb = llcp_add_tlv(skb, rw_tlv, rw_tlv_length);
skb_queue_tail(&local->tx_queue, skb);
return 0;
+
+error_tlv:
+ pr_err("error %d\n", err);
+
+ kfree(miux_tlv);
+ kfree(rw_tlv);
+
+ return err;
}
int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason)
@@ -397,3 +444,87 @@ int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock)
return 0;
}
+
+int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
+ struct msghdr *msg, size_t len)
+{
+ struct sk_buff *pdu;
+ struct sock *sk = &sock->sk;
+ struct nfc_llcp_local *local;
+ size_t frag_len = 0, remaining_len;
+ u8 *msg_data, *msg_ptr;
+
+ pr_debug("Send I frame len %zd\n", len);
+
+ local = sock->local;
+ if (local == NULL)
+ return -ENODEV;
+
+ msg_data = kzalloc(len, GFP_KERNEL);
+ if (msg_data == NULL)
+ return -ENOMEM;
+
+ if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) {
+ kfree(msg_data);
+ return -EFAULT;
+ }
+
+ remaining_len = len;
+ msg_ptr = msg_data;
+
+ while (remaining_len > 0) {
+
+ frag_len = min_t(u16, local->remote_miu, remaining_len);
+
+ pr_debug("Fragment %zd bytes remaining %zd",
+ frag_len, remaining_len);
+
+ pdu = llcp_allocate_pdu(sock, LLCP_PDU_I,
+ frag_len + LLCP_SEQUENCE_SIZE);
+ if (pdu == NULL)
+ return -ENOMEM;
+
+ skb_put(pdu, LLCP_SEQUENCE_SIZE);
+
+ memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
+
+ skb_queue_head(&sock->tx_queue, pdu);
+
+ lock_sock(sk);
+
+ nfc_llcp_queue_i_frames(sock);
+
+ release_sock(sk);
+
+ remaining_len -= frag_len;
+ msg_ptr += len;
+ }
+
+ kfree(msg_data);
+
+ return 0;
+}
+
+int nfc_llcp_send_rr(struct nfc_llcp_sock *sock)
+{
+ struct sk_buff *skb;
+ struct nfc_llcp_local *local;
+
+ pr_debug("Send rr nr %d\n", sock->recv_n);
+
+ local = sock->local;
+ if (local == NULL)
+ return -ENODEV;
+
+ skb = llcp_allocate_pdu(sock, LLCP_PDU_RR, LLCP_SEQUENCE_SIZE);
+ if (skb == NULL)
+ return -ENOMEM;
+
+ skb_put(skb, LLCP_SEQUENCE_SIZE);
+
+ skb->data[2] = sock->recv_n % 16;
+
+ skb_queue_head(&local->tx_queue, skb);
+
+ return 0;
+}
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 1d32680..17a578f 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -37,7 +37,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
struct sock *sk, *parent_sk;
int i;
-
mutex_lock(&local->socket_lock);
for (i = 0; i < LLCP_MAX_SAP; i++) {
@@ -47,7 +46,7 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
/* Release all child sockets */
list_for_each_entry_safe(s, n, &parent->list, list) {
- list_del(&s->list);
+ list_del_init(&s->list);
sk = &s->sk;
lock_sock(sk);
@@ -56,9 +55,12 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
nfc_put_device(s->dev);
sk->sk_state = LLCP_CLOSED;
- sock_set_flag(sk, SOCK_DEAD);
release_sock(sk);
+
+ sock_orphan(sk);
+
+ s->local = NULL;
}
parent_sk = &parent->sk;
@@ -70,18 +72,19 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
struct sock *accept_sk;
list_for_each_entry_safe(lsk, n, &parent->accept_queue,
- accept_queue) {
+ accept_queue) {
accept_sk = &lsk->sk;
lock_sock(accept_sk);
nfc_llcp_accept_unlink(accept_sk);
accept_sk->sk_state = LLCP_CLOSED;
- sock_set_flag(accept_sk, SOCK_DEAD);
release_sock(accept_sk);
sock_orphan(accept_sk);
+
+ lsk->local = NULL;
}
}
@@ -89,18 +92,32 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local)
nfc_put_device(parent->dev);
parent_sk->sk_state = LLCP_CLOSED;
- sock_set_flag(parent_sk, SOCK_DEAD);
release_sock(parent_sk);
+
+ sock_orphan(parent_sk);
+
+ parent->local = NULL;
}
mutex_unlock(&local->socket_lock);
}
+static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local)
+{
+ mutex_lock(&local->sdp_lock);
+
+ local->local_wks = 0;
+ local->local_sdp = 0;
+ local->local_sap = 0;
+
+ mutex_unlock(&local->sdp_lock);
+}
+
static void nfc_llcp_timeout_work(struct work_struct *work)
{
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
- timeout_work);
+ timeout_work);
nfc_dep_link_down(local->dev);
}
@@ -146,7 +163,7 @@ static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len)
num_wks = ARRAY_SIZE(wks);
- for (sap = 0 ; sap < num_wks; sap++) {
+ for (sap = 0; sap < num_wks; sap++) {
if (wks[sap] == NULL)
continue;
@@ -158,13 +175,13 @@ static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len)
}
u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
- struct nfc_llcp_sock *sock)
+ struct nfc_llcp_sock *sock)
{
mutex_lock(&local->sdp_lock);
if (sock->service_name != NULL && sock->service_name_len > 0) {
int ssap = nfc_llcp_wks_sap(sock->service_name,
- sock->service_name_len);
+ sock->service_name_len);
if (ssap > 0) {
pr_debug("WKS %d\n", ssap);
@@ -176,7 +193,7 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
return LLCP_SAP_MAX;
}
- set_bit(BIT(ssap), &local->local_wks);
+ set_bit(ssap, &local->local_wks);
mutex_unlock(&local->sdp_lock);
return ssap;
@@ -195,25 +212,25 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap);
- set_bit(BIT(ssap), &local->local_sdp);
+ set_bit(ssap, &local->local_sdp);
mutex_unlock(&local->sdp_lock);
return LLCP_WKS_NUM_SAP + ssap;
} else if (sock->ssap != 0) {
if (sock->ssap < LLCP_WKS_NUM_SAP) {
- if (!(local->local_wks & BIT(sock->ssap))) {
- set_bit(BIT(sock->ssap), &local->local_wks);
+ if (!test_bit(sock->ssap, &local->local_wks)) {
+ set_bit(sock->ssap, &local->local_wks);
mutex_unlock(&local->sdp_lock);
return sock->ssap;
}
} else if (sock->ssap < LLCP_SDP_NUM_SAP) {
- if (!(local->local_sdp &
- BIT(sock->ssap - LLCP_WKS_NUM_SAP))) {
- set_bit(BIT(sock->ssap - LLCP_WKS_NUM_SAP),
- &local->local_sdp);
+ if (!test_bit(sock->ssap - LLCP_WKS_NUM_SAP,
+ &local->local_sdp)) {
+ set_bit(sock->ssap - LLCP_WKS_NUM_SAP,
+ &local->local_sdp);
mutex_unlock(&local->sdp_lock);
return sock->ssap;
@@ -238,7 +255,7 @@ u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local)
return LLCP_SAP_MAX;
}
- set_bit(BIT(local_ssap), &local->local_sap);
+ set_bit(local_ssap, &local->local_sap);
mutex_unlock(&local->sdp_lock);
@@ -265,12 +282,12 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap)
mutex_lock(&local->sdp_lock);
- clear_bit(1 << local_ssap, sdp);
+ clear_bit(local_ssap, sdp);
mutex_unlock(&local->sdp_lock);
}
-u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, u8 *general_bytes_len)
+u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len)
{
struct nfc_llcp_local *local;
@@ -294,7 +311,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
version = LLCP_VERSION_11;
version_tlv = nfc_llcp_build_tlv(LLCP_TLV_VERSION, &version,
- 1, &version_length);
+ 1, &version_length);
gb_len += version_length;
/* 1500 ms */
@@ -304,7 +321,7 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local)
pr_debug("Local wks 0x%lx\n", local->local_wks);
wks_tlv = nfc_llcp_build_tlv(LLCP_TLV_WKS, (u8 *)&local->local_wks, 2,
- &wks_length);
+ &wks_length);
gb_len += wks_length;
gb_len += ARRAY_SIZE(llcp_magic);
@@ -349,8 +366,7 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
memcpy(local->remote_gb, gb, gb_len);
local->remote_gb_len = gb_len;
- if (local->remote_gb == NULL ||
- local->remote_gb_len == 0)
+ if (local->remote_gb == NULL || local->remote_gb_len == 0)
return -ENODEV;
if (memcmp(local->remote_gb, llcp_magic, 3)) {
@@ -359,26 +375,27 @@ int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
}
return nfc_llcp_parse_tlv(local,
- &local->remote_gb[3], local->remote_gb_len - 3);
+ &local->remote_gb[3],
+ 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);
+ tx_work);
struct sk_buff *skb;
skb = skb_dequeue(&local->tx_queue);
if (skb != NULL) {
pr_debug("Sending pending skb\n");
nfc_data_exchange(local->dev, local->target_idx,
- skb, nfc_llcp_recv, local);
+ skb, nfc_llcp_recv, local);
} else {
nfc_llcp_send_symm(local->dev);
}
mod_timer(&local->link_timer,
- jiffies + msecs_to_jiffies(local->remote_lto));
+ jiffies + msecs_to_jiffies(local->remote_lto));
}
static u8 nfc_llcp_dsap(struct sk_buff *pdu)
@@ -408,13 +425,13 @@ static u8 nfc_llcp_nr(struct sk_buff *pdu)
static void nfc_llcp_set_nrns(struct nfc_llcp_sock *sock, struct sk_buff *pdu)
{
- pdu->data[2] = (sock->send_n << 4) | ((sock->recv_n - 1) % 16);
+ pdu->data[2] = (sock->send_n << 4) | (sock->recv_n % 16);
sock->send_n = (sock->send_n + 1) % 16;
sock->recv_ack_n = (sock->recv_n - 1) % 16;
}
static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
- u8 ssap, u8 dsap)
+ u8 ssap, u8 dsap)
{
struct nfc_llcp_sock *sock, *llcp_sock, *n;
@@ -438,7 +455,7 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
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);
+ &llcp_sock->sk, llcp_sock->dsap);
if (llcp_sock->dsap == dsap) {
sock_hold(&llcp_sock->sk);
mutex_unlock(&local->socket_lock);
@@ -482,7 +499,7 @@ static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len)
}
static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
struct sock *new_sk, *parent;
struct nfc_llcp_sock *sock, *new_sock;
@@ -494,7 +511,7 @@ 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);
+ skb->len - LLCP_HEADER_SIZE);
if (dsap != LLCP_SAP_SDP) {
bound_sap = dsap;
@@ -513,7 +530,7 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
lock_sock(&sock->sk);
if (sock->dsap == LLCP_SAP_SDP &&
- sock->sk.sk_state == LLCP_LISTEN)
+ sock->sk.sk_state == LLCP_LISTEN)
goto enqueue;
} else {
u8 *sn;
@@ -529,23 +546,23 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
mutex_lock(&local->socket_lock);
for (bound_sap = 0; bound_sap < LLCP_LOCAL_SAP_OFFSET;
- bound_sap++) {
+ bound_sap++) {
sock = local->sockets[bound_sap];
if (sock == NULL)
continue;
if (sock->service_name == NULL ||
- sock->service_name_len == 0)
+ 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)) {
+ sock->sk.sk_state == LLCP_LISTEN &&
+ !memcmp(sn, sock->service_name, sn_len)) {
pr_debug("Found service name at SAP %d\n",
- bound_sap);
+ bound_sap);
sock_hold(&sock->sk);
mutex_unlock(&local->socket_lock);
@@ -570,8 +587,7 @@ enqueue:
goto fail;
}
- new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type,
- GFP_ATOMIC);
+ new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC);
if (new_sk == NULL) {
reason = LLCP_DM_REJ;
release_sock(&sock->sk);
@@ -616,8 +632,39 @@ fail:
}
+int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock)
+{
+ int nr_frames = 0;
+ struct nfc_llcp_local *local = sock->local;
+
+ 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);
+
+ /* Try to queue some I frames for transmission */
+ while (sock->remote_ready &&
+ skb_queue_len(&sock->tx_pending_queue) < local->remote_rw) {
+ struct sk_buff *pdu, *pending_pdu;
+
+ pdu = skb_dequeue(&sock->tx_queue);
+ if (pdu == NULL)
+ break;
+
+ /* 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++;
+ }
+
+ return nr_frames;
+}
+
static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
struct nfc_llcp_sock *llcp_sock;
struct sock *sk;
@@ -644,15 +691,15 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
nfc_llcp_sock_put(llcp_sock);
}
- if (ns == llcp_sock->recv_n)
- llcp_sock->recv_n = (llcp_sock->recv_n + 1) % 16;
- else
- pr_err("Received out of sequence I PDU\n");
-
/* Pass the payload upstream */
if (ptype == LLCP_PDU_I) {
pr_debug("I frame, queueing on %p\n", &llcp_sock->sk);
+ if (ns == llcp_sock->recv_n)
+ llcp_sock->recv_n = (llcp_sock->recv_n + 1) % 16;
+ else
+ pr_err("Received out of sequence I PDU\n");
+
skb_pull(skb, LLCP_HEADER_SIZE + LLCP_SEQUENCE_SIZE);
if (sock_queue_rcv_skb(&llcp_sock->sk, skb)) {
pr_err("receive queue is full\n");
@@ -673,30 +720,20 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
}
}
- /* Queue some I frames for transmission */
- while (llcp_sock->remote_ready &&
- skb_queue_len(&llcp_sock->tx_pending_queue) <= local->remote_rw) {
- struct sk_buff *pdu, *pending_pdu;
-
- pdu = skb_dequeue(&llcp_sock->tx_queue);
- if (pdu == NULL)
- break;
-
- /* Update N(S)/N(R) */
- nfc_llcp_set_nrns(llcp_sock, pdu);
+ if (ptype == LLCP_PDU_RR)
+ llcp_sock->remote_ready = true;
+ else if (ptype == LLCP_PDU_RNR)
+ llcp_sock->remote_ready = false;
- pending_pdu = skb_clone(pdu, GFP_KERNEL);
-
- skb_queue_tail(&local->tx_queue, pdu);
- skb_queue_tail(&llcp_sock->tx_pending_queue, pending_pdu);
- }
+ if (nfc_llcp_queue_i_frames(llcp_sock) == 0)
+ nfc_llcp_send_rr(llcp_sock);
release_sock(sk);
nfc_llcp_sock_put(llcp_sock);
}
static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
struct nfc_llcp_sock *llcp_sock;
struct sock *sk;
@@ -718,7 +755,6 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
nfc_llcp_sock_put(llcp_sock);
}
-
if (sk->sk_state == LLCP_CONNECTED) {
nfc_put_device(local->dev);
sk->sk_state = LLCP_CLOSED;
@@ -731,13 +767,11 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
nfc_llcp_sock_put(llcp_sock);
}
-static void nfc_llcp_recv_cc(struct nfc_llcp_local *local,
- struct sk_buff *skb)
+static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
{
struct nfc_llcp_sock *llcp_sock;
u8 dsap, ssap;
-
dsap = nfc_llcp_dsap(skb);
ssap = nfc_llcp_ssap(skb);
@@ -756,7 +790,7 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local,
llcp_sock->dsap = ssap;
nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
- skb->len - LLCP_HEADER_SIZE);
+ skb->len - LLCP_HEADER_SIZE);
nfc_llcp_sock_put(llcp_sock);
}
@@ -764,7 +798,7 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local,
static void nfc_llcp_rx_work(struct work_struct *work)
{
struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
- rx_work);
+ rx_work);
u8 dsap, ssap, ptype;
struct sk_buff *skb;
@@ -802,6 +836,7 @@ static void nfc_llcp_rx_work(struct work_struct *work)
case LLCP_PDU_I:
case LLCP_PDU_RR:
+ case LLCP_PDU_RNR:
pr_debug("I frame\n");
nfc_llcp_recv_hdlc(local, skb);
break;
@@ -821,7 +856,7 @@ void nfc_llcp_recv(void *data, struct sk_buff *skb, int err)
pr_debug("Received an LLCP PDU\n");
if (err < 0) {
- pr_err("err %d", err);
+ pr_err("err %d\n", err);
return;
}
@@ -840,6 +875,8 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev)
if (local == NULL)
return;
+ nfc_llcp_clear_sdp(local);
+
/* Close and purge all existing sockets */
nfc_llcp_socket_release(local);
}
@@ -865,7 +902,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx,
queue_work(local->tx_wq, &local->tx_work);
} else {
mod_timer(&local->link_timer,
- jiffies + msecs_to_jiffies(local->remote_lto));
+ jiffies + msecs_to_jiffies(local->remote_lto));
}
}
@@ -891,8 +928,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
skb_queue_head_init(&local->tx_queue);
INIT_WORK(&local->tx_work, nfc_llcp_tx_work);
snprintf(name, sizeof(name), "%s_llcp_tx_wq", dev_name(dev));
- local->tx_wq = alloc_workqueue(name,
- WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ local->tx_wq =
+ alloc_workqueue(name,
+ WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
+ 1);
if (local->tx_wq == NULL) {
err = -ENOMEM;
goto err_local;
@@ -901,8 +940,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
local->rx_pending = NULL;
INIT_WORK(&local->rx_work, nfc_llcp_rx_work);
snprintf(name, sizeof(name), "%s_llcp_rx_wq", dev_name(dev));
- local->rx_wq = alloc_workqueue(name,
- WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ local->rx_wq =
+ alloc_workqueue(name,
+ WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
+ 1);
if (local->rx_wq == NULL) {
err = -ENOMEM;
goto err_tx_wq;
@@ -910,8 +951,10 @@ int nfc_llcp_register_device(struct nfc_dev *ndev)
INIT_WORK(&local->timeout_work, nfc_llcp_timeout_work);
snprintf(name, sizeof(name), "%s_llcp_timeout_wq", dev_name(dev));
- local->timeout_wq = alloc_workqueue(name,
- WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ local->timeout_wq =
+ alloc_workqueue(name,
+ WQ_NON_REENTRANT | WQ_UNBOUND | WQ_MEM_RECLAIM,
+ 1);
if (local->timeout_wq == NULL) {
err = -ENOMEM;
goto err_rx_wq;
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h
index 0ad2e33..50680ce 100644
--- a/net/nfc/llcp/llcp.h
+++ b/net/nfc/llcp/llcp.h
@@ -28,6 +28,10 @@ enum llcp_state {
#define LLCP_DEFAULT_RW 1
#define LLCP_DEFAULT_MIU 128
+#define LLCP_MAX_LTO 0xff
+#define LLCP_MAX_RW 15
+#define LLCP_MAX_MIUX 0x7ff
+
#define LLCP_WKS_NUM_SAP 16
#define LLCP_SDP_NUM_SAP 16
#define LLCP_LOCAL_NUM_SAP 32
@@ -162,9 +166,10 @@ struct nfc_llcp_sock {
struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local,
- struct nfc_llcp_sock *sock);
+ struct nfc_llcp_sock *sock);
u8 nfc_llcp_get_local_ssap(struct nfc_llcp_local *local);
void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap);
+int nfc_llcp_queue_i_frames(struct nfc_llcp_sock *sock);
/* Sock API */
struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp);
@@ -175,7 +180,7 @@ 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);
+ u8 *tlv_array, u16 tlv_array_len);
/* Commands API */
void nfc_llcp_recv(void *data, struct sk_buff *skb, int err);
@@ -187,6 +192,9 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock);
int nfc_llcp_send_cc(struct nfc_llcp_sock *sock);
int nfc_llcp_send_dm(struct nfc_llcp_local *local, u8 ssap, u8 dsap, u8 reason);
int nfc_llcp_send_disconnect(struct nfc_llcp_sock *sock);
+int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
+ struct msghdr *msg, size_t len);
+int nfc_llcp_send_rr(struct nfc_llcp_sock *sock);
/* Socket API */
int __init nfc_llcp_sock_init(void);
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index f738ccd..c13e02e 100644
--- a/net/nfc/llcp/sock.c
+++ b/net/nfc/llcp/sock.c
@@ -78,9 +78,11 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
llcp_sock->local = local;
llcp_sock->nfc_protocol = llcp_addr.nfc_protocol;
llcp_sock->service_name_len = min_t(unsigned int,
- llcp_addr.service_name_len, NFC_LLCP_MAX_SERVICE_NAME);
+ llcp_addr.service_name_len,
+ NFC_LLCP_MAX_SERVICE_NAME);
llcp_sock->service_name = kmemdup(llcp_addr.service_name,
- llcp_sock->service_name_len, GFP_KERNEL);
+ llcp_sock->service_name_len,
+ GFP_KERNEL);
llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock);
if (llcp_sock->ssap == LLCP_MAX_SAP)
@@ -110,7 +112,7 @@ static int llcp_sock_listen(struct socket *sock, int backlog)
lock_sock(sk);
if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
- || sk->sk_state != LLCP_BOUND) {
+ || sk->sk_state != LLCP_BOUND) {
ret = -EBADFD;
goto error;
}
@@ -149,13 +151,13 @@ void nfc_llcp_accept_enqueue(struct sock *parent, struct sock *sk)
sock_hold(sk);
list_add_tail(&llcp_sock->accept_queue,
- &llcp_sock_parent->accept_queue);
+ &llcp_sock_parent->accept_queue);
llcp_sock->parent = parent;
sk_acceptq_added(parent);
}
struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
- struct socket *newsock)
+ struct socket *newsock)
{
struct nfc_llcp_sock *lsk, *n, *llcp_parent;
struct sock *sk;
@@ -163,7 +165,7 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
llcp_parent = nfc_llcp_sock(parent);
list_for_each_entry_safe(lsk, n, &llcp_parent->accept_queue,
- accept_queue) {
+ accept_queue) {
sk = &lsk->sk;
lock_sock(sk);
@@ -192,7 +194,7 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
}
static int llcp_sock_accept(struct socket *sock, struct socket *newsock,
- int flags)
+ int flags)
{
DECLARE_WAITQUEUE(wait, current);
struct sock *sk = sock->sk, *new_sk;
@@ -248,7 +250,7 @@ error:
static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr,
int *len, int peer)
{
- struct sockaddr_nfc_llcp *llcp_addr = (struct sockaddr_nfc_llcp *) addr;
+ struct sockaddr_nfc_llcp *llcp_addr = (struct sockaddr_nfc_llcp *)addr;
struct sock *sk = sock->sk;
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
@@ -262,7 +264,7 @@ static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr,
llcp_addr->ssap = llcp_sock->ssap;
llcp_addr->service_name_len = llcp_sock->service_name_len;
memcpy(llcp_addr->service_name, llcp_sock->service_name,
- llcp_addr->service_name_len);
+ llcp_addr->service_name_len);
return 0;
}
@@ -275,7 +277,7 @@ static inline unsigned int llcp_accept_poll(struct sock *parent)
parent_sock = nfc_llcp_sock(parent);
list_for_each_entry_safe(llcp_sock, n, &parent_sock->accept_queue,
- accept_queue) {
+ accept_queue) {
sk = &llcp_sock->sk;
if (sk->sk_state == LLCP_CONNECTED)
@@ -286,7 +288,7 @@ static inline unsigned int llcp_accept_poll(struct sock *parent)
}
static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
- poll_table *wait)
+ poll_table *wait)
{
struct sock *sk = sock->sk;
unsigned int mask = 0;
@@ -315,6 +317,7 @@ static int llcp_sock_release(struct socket *sock)
struct sock *sk = sock->sk;
struct nfc_llcp_local *local;
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
+ int err = 0;
if (!sk)
return 0;
@@ -322,25 +325,17 @@ static int llcp_sock_release(struct socket *sock)
pr_debug("%p\n", sk);
local = llcp_sock->local;
- if (local == NULL)
- return -ENODEV;
+ if (local == NULL) {
+ err = -ENODEV;
+ goto out;
+ }
mutex_lock(&local->socket_lock);
- if (llcp_sock == local->sockets[llcp_sock->ssap]) {
+ if (llcp_sock == local->sockets[llcp_sock->ssap])
local->sockets[llcp_sock->ssap] = NULL;
- } else {
- struct nfc_llcp_sock *parent, *s, *n;
-
- parent = local->sockets[llcp_sock->ssap];
-
- list_for_each_entry_safe(s, n, &parent->list, list)
- if (llcp_sock == s) {
- list_del(&s->list);
- break;
- }
-
- }
+ else
+ list_del_init(&llcp_sock->list);
mutex_unlock(&local->socket_lock);
@@ -355,7 +350,7 @@ static int llcp_sock_release(struct socket *sock)
struct sock *accept_sk;
list_for_each_entry_safe(lsk, n, &llcp_sock->accept_queue,
- accept_queue) {
+ accept_queue) {
accept_sk = &lsk->sk;
lock_sock(accept_sk);
@@ -364,31 +359,27 @@ static int llcp_sock_release(struct socket *sock)
release_sock(accept_sk);
- sock_set_flag(sk, SOCK_DEAD);
sock_orphan(accept_sk);
- sock_put(accept_sk);
}
}
/* 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)
+ && 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);
- sock_set_flag(sk, SOCK_DEAD);
-
release_sock(sk);
+out:
sock_orphan(sk);
sock_put(sk);
- return 0;
+ return err;
}
static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
- int len, int flags)
+ int len, int flags)
{
struct sock *sk = sock->sk;
struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
@@ -400,7 +391,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
pr_debug("sock %p sk %p flags 0x%x\n", sock, sk, flags);
if (!addr || len < sizeof(struct sockaddr_nfc) ||
- addr->sa_family != AF_NFC) {
+ addr->sa_family != AF_NFC) {
pr_err("Invalid socket\n");
return -EINVAL;
}
@@ -411,7 +402,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
}
pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n", addr->dev_idx,
- addr->target_idx, addr->nfc_protocol);
+ addr->target_idx, addr->nfc_protocol);
lock_sock(sk);
@@ -441,7 +432,7 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
device_unlock(&dev->dev);
if (local->rf_mode == NFC_RF_INITIATOR &&
- addr->target_idx != local->target_idx) {
+ addr->target_idx != local->target_idx) {
ret = -ENOLINK;
goto put_dev;
}
@@ -459,9 +450,11 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
llcp_sock->dsap = LLCP_SAP_SDP;
llcp_sock->nfc_protocol = addr->nfc_protocol;
llcp_sock->service_name_len = min_t(unsigned int,
- addr->service_name_len, NFC_LLCP_MAX_SERVICE_NAME);
+ addr->service_name_len,
+ NFC_LLCP_MAX_SERVICE_NAME);
llcp_sock->service_name = kmemdup(addr->service_name,
- llcp_sock->service_name_len, GFP_KERNEL);
+ llcp_sock->service_name_len,
+ GFP_KERNEL);
local->sockets[llcp_sock->ssap] = llcp_sock;
@@ -482,6 +475,34 @@ error:
return ret;
}
+static int llcp_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t len)
+{
+ struct sock *sk = sock->sk;
+ struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
+ int ret;
+
+ pr_debug("sock %p sk %p", sock, sk);
+
+ ret = sock_error(sk);
+ if (ret)
+ return ret;
+
+ if (msg->msg_flags & MSG_OOB)
+ return -EOPNOTSUPP;
+
+ lock_sock(sk);
+
+ if (sk->sk_state != LLCP_CONNECTED) {
+ release_sock(sk);
+ return -ENOTCONN;
+ }
+
+ release_sock(sk);
+
+ return nfc_llcp_send_i_frame(llcp_sock, msg, len);
+}
+
static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len, int flags)
{
@@ -496,7 +517,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
lock_sock(sk);
if (sk->sk_state == LLCP_CLOSED &&
- skb_queue_empty(&sk->sk_receive_queue)) {
+ skb_queue_empty(&sk->sk_receive_queue)) {
release_sock(sk);
return 0;
}
@@ -509,7 +530,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
skb = skb_recv_datagram(sk, flags, noblock, &err);
if (!skb) {
pr_err("Recv datagram failed state %d %d %d",
- sk->sk_state, err, sock_error(sk));
+ sk->sk_state, err, sock_error(sk));
if (sk->sk_shutdown & RCV_SHUTDOWN)
return 0;
@@ -517,7 +538,7 @@ static int llcp_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
return err;
}
- rlen = skb->len; /* real length of skb */
+ rlen = skb->len; /* real length of skb */
copied = min_t(unsigned int, rlen, len);
cskb = skb;
@@ -567,7 +588,7 @@ static const struct proto_ops llcp_sock_ops = {
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
.getsockopt = sock_no_getsockopt,
- .sendmsg = sock_no_sendmsg,
+ .sendmsg = llcp_sock_sendmsg,
.recvmsg = llcp_sock_recvmsg,
.mmap = sock_no_mmap,
};
@@ -627,6 +648,8 @@ 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);
@@ -635,11 +658,16 @@ void nfc_llcp_sock_free(struct nfc_llcp_sock *sock)
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);
+
sock->parent = NULL;
}
static int llcp_sock_create(struct net *net, struct socket *sock,
- const struct nfc_protocol *nfc_proto)
+ const struct nfc_protocol *nfc_proto)
{
struct sock *sk;
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 7650139..9ec065b 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -66,9 +66,8 @@ static void nci_req_cancel(struct nci_dev *ndev, int err)
/* Execute request and wait for completion. */
static int __nci_request(struct nci_dev *ndev,
- void (*req)(struct nci_dev *ndev, unsigned long opt),
- unsigned long opt,
- __u32 timeout)
+ void (*req)(struct nci_dev *ndev, unsigned long opt),
+ unsigned long opt, __u32 timeout)
{
int rc = 0;
long completion_rc;
@@ -77,9 +76,9 @@ static int __nci_request(struct nci_dev *ndev,
init_completion(&ndev->req_completion);
req(ndev, opt);
- completion_rc = wait_for_completion_interruptible_timeout(
- &ndev->req_completion,
- timeout);
+ completion_rc =
+ wait_for_completion_interruptible_timeout(&ndev->req_completion,
+ timeout);
pr_debug("wait_for_completion return %ld\n", completion_rc);
@@ -110,8 +109,9 @@ static int __nci_request(struct nci_dev *ndev,
}
static inline int nci_request(struct nci_dev *ndev,
- void (*req)(struct nci_dev *ndev, unsigned long opt),
- unsigned long opt, __u32 timeout)
+ void (*req)(struct nci_dev *ndev,
+ unsigned long opt),
+ unsigned long opt, __u32 timeout)
{
int rc;
@@ -152,14 +152,14 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
/* by default mapping is set to NCI_RF_INTERFACE_FRAME */
for (i = 0; i < ndev->num_supported_rf_interfaces; i++) {
if (ndev->supported_rf_interfaces[i] ==
- NCI_RF_INTERFACE_ISO_DEP) {
+ NCI_RF_INTERFACE_ISO_DEP) {
cfg[*num].rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
cfg[*num].mode = NCI_DISC_MAP_MODE_POLL |
NCI_DISC_MAP_MODE_LISTEN;
cfg[*num].rf_interface = NCI_RF_INTERFACE_ISO_DEP;
(*num)++;
} else if (ndev->supported_rf_interfaces[i] ==
- NCI_RF_INTERFACE_NFC_DEP) {
+ NCI_RF_INTERFACE_NFC_DEP) {
cfg[*num].rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
cfg[*num].mode = NCI_DISC_MAP_MODE_POLL |
NCI_DISC_MAP_MODE_LISTEN;
@@ -172,8 +172,7 @@ static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
}
nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_MAP_CMD,
- (1 + ((*num)*sizeof(struct disc_map_config))),
- &cmd);
+ (1 + ((*num) * sizeof(struct disc_map_config))), &cmd);
}
static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
@@ -184,36 +183,68 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
cmd.num_disc_configs = 0;
if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
- (protocols & NFC_PROTO_JEWEL_MASK
- || protocols & NFC_PROTO_MIFARE_MASK
- || protocols & NFC_PROTO_ISO14443_MASK
- || protocols & NFC_PROTO_NFC_DEP_MASK)) {
+ (protocols & NFC_PROTO_JEWEL_MASK
+ || protocols & NFC_PROTO_MIFARE_MASK
+ || protocols & NFC_PROTO_ISO14443_MASK
+ || protocols & NFC_PROTO_NFC_DEP_MASK)) {
cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
- NCI_NFC_A_PASSIVE_POLL_MODE;
+ NCI_NFC_A_PASSIVE_POLL_MODE;
cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
cmd.num_disc_configs++;
}
if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
- (protocols & NFC_PROTO_ISO14443_MASK)) {
+ (protocols & NFC_PROTO_ISO14443_MASK)) {
cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
- NCI_NFC_B_PASSIVE_POLL_MODE;
+ NCI_NFC_B_PASSIVE_POLL_MODE;
cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
cmd.num_disc_configs++;
}
if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
- (protocols & NFC_PROTO_FELICA_MASK
- || protocols & NFC_PROTO_NFC_DEP_MASK)) {
+ (protocols & NFC_PROTO_FELICA_MASK
+ || protocols & NFC_PROTO_NFC_DEP_MASK)) {
cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
- NCI_NFC_F_PASSIVE_POLL_MODE;
+ NCI_NFC_F_PASSIVE_POLL_MODE;
cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
cmd.num_disc_configs++;
}
nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_CMD,
- (1 + (cmd.num_disc_configs*sizeof(struct disc_config))),
- &cmd);
+ (1 + (cmd.num_disc_configs * sizeof(struct disc_config))),
+ &cmd);
+}
+
+struct nci_rf_discover_select_param {
+ __u8 rf_discovery_id;
+ __u8 rf_protocol;
+};
+
+static void nci_rf_discover_select_req(struct nci_dev *ndev, unsigned long opt)
+{
+ struct nci_rf_discover_select_param *param =
+ (struct nci_rf_discover_select_param *)opt;
+ struct nci_rf_discover_select_cmd cmd;
+
+ cmd.rf_discovery_id = param->rf_discovery_id;
+ cmd.rf_protocol = param->rf_protocol;
+
+ switch (cmd.rf_protocol) {
+ case NCI_RF_PROTOCOL_ISO_DEP:
+ cmd.rf_interface = NCI_RF_INTERFACE_ISO_DEP;
+ break;
+
+ case NCI_RF_PROTOCOL_NFC_DEP:
+ cmd.rf_interface = NCI_RF_INTERFACE_NFC_DEP;
+ break;
+
+ default:
+ cmd.rf_interface = NCI_RF_INTERFACE_FRAME;
+ break;
+ }
+
+ nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_SELECT_CMD,
+ sizeof(struct nci_rf_discover_select_cmd), &cmd);
}
static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt)
@@ -223,8 +254,7 @@ static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt)
cmd.type = NCI_DEACTIVATE_TYPE_IDLE_MODE;
nci_send_cmd(ndev, NCI_OP_RF_DEACTIVATE_CMD,
- sizeof(struct nci_rf_deactivate_cmd),
- &cmd);
+ sizeof(struct nci_rf_deactivate_cmd), &cmd);
}
static int nci_open_device(struct nci_dev *ndev)
@@ -248,22 +278,24 @@ static int nci_open_device(struct nci_dev *ndev)
set_bit(NCI_INIT, &ndev->flags);
rc = __nci_request(ndev, nci_reset_req, 0,
- msecs_to_jiffies(NCI_RESET_TIMEOUT));
+ msecs_to_jiffies(NCI_RESET_TIMEOUT));
if (!rc) {
rc = __nci_request(ndev, nci_init_req, 0,
- msecs_to_jiffies(NCI_INIT_TIMEOUT));
+ msecs_to_jiffies(NCI_INIT_TIMEOUT));
}
if (!rc) {
rc = __nci_request(ndev, nci_init_complete_req, 0,
- msecs_to_jiffies(NCI_INIT_TIMEOUT));
+ msecs_to_jiffies(NCI_INIT_TIMEOUT));
}
clear_bit(NCI_INIT, &ndev->flags);
if (!rc) {
set_bit(NCI_UP, &ndev->flags);
+ nci_clear_target_list(ndev);
+ atomic_set(&ndev->state, NCI_IDLE);
} else {
/* Init failed, cleanup */
skb_queue_purge(&ndev->cmd_q);
@@ -286,6 +318,7 @@ static int nci_close_device(struct nci_dev *ndev)
if (!test_and_clear_bit(NCI_UP, &ndev->flags)) {
del_timer_sync(&ndev->cmd_timer);
+ del_timer_sync(&ndev->data_timer);
mutex_unlock(&ndev->req_lock);
return 0;
}
@@ -304,7 +337,7 @@ static int nci_close_device(struct nci_dev *ndev)
set_bit(NCI_INIT, &ndev->flags);
__nci_request(ndev, nci_reset_req, 0,
- msecs_to_jiffies(NCI_RESET_TIMEOUT));
+ msecs_to_jiffies(NCI_RESET_TIMEOUT));
clear_bit(NCI_INIT, &ndev->flags);
/* Flush cmd wq */
@@ -331,6 +364,15 @@ static void nci_cmd_timer(unsigned long arg)
queue_work(ndev->cmd_wq, &ndev->cmd_work);
}
+/* NCI data exchange timer function */
+static void nci_data_timer(unsigned long arg)
+{
+ struct nci_dev *ndev = (void *) arg;
+
+ set_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
+ queue_work(ndev->rx_wq, &ndev->rx_work);
+}
+
static int nci_dev_up(struct nfc_dev *nfc_dev)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
@@ -350,7 +392,8 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
int rc;
- if (test_bit(NCI_DISCOVERY, &ndev->flags)) {
+ if ((atomic_read(&ndev->state) == NCI_DISCOVERY) ||
+ (atomic_read(&ndev->state) == NCI_W4_ALL_DISCOVERIES)) {
pr_err("unable to start poll, since poll is already active\n");
return -EBUSY;
}
@@ -360,17 +403,18 @@ static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
return -EBUSY;
}
- if (test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
- pr_debug("target is active, implicitly deactivate...\n");
+ if ((atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) ||
+ (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) {
+ pr_debug("target active or w4 select, implicitly deactivate\n");
rc = nci_request(ndev, nci_rf_deactivate_req, 0,
- msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
+ msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
if (rc)
return -EBUSY;
}
rc = nci_request(ndev, nci_rf_discover_req, protocols,
- msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
+ msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
if (!rc)
ndev->poll_prots = protocols;
@@ -382,23 +426,29 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
- if (!test_bit(NCI_DISCOVERY, &ndev->flags)) {
+ if ((atomic_read(&ndev->state) != NCI_DISCOVERY) &&
+ (atomic_read(&ndev->state) != NCI_W4_ALL_DISCOVERIES)) {
pr_err("unable to stop poll, since poll is not active\n");
return;
}
nci_request(ndev, nci_rf_deactivate_req, 0,
- msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
+ msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
}
static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
- __u32 protocol)
+ __u32 protocol)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+ struct nci_rf_discover_select_param param;
+ struct nfc_target *target = NULL;
+ int i;
+ int rc = 0;
pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol);
- if (!test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
+ if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) &&
+ (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
pr_err("there is no available target to activate\n");
return -EINVAL;
}
@@ -408,16 +458,47 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
return -EBUSY;
}
- if (!(ndev->target_available_prots & (1 << protocol))) {
+ for (i = 0; i < ndev->n_targets; i++) {
+ if (ndev->targets[i].idx == target_idx) {
+ target = &ndev->targets[i];
+ break;
+ }
+ }
+
+ if (!target) {
+ pr_err("unable to find the selected target\n");
+ return -EINVAL;
+ }
+
+ if (!(target->supported_protocols & (1 << protocol))) {
pr_err("target does not support the requested protocol 0x%x\n",
protocol);
return -EINVAL;
}
- ndev->target_active_prot = protocol;
- ndev->target_available_prots = 0;
+ if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) {
+ param.rf_discovery_id = target->idx;
- return 0;
+ if (protocol == NFC_PROTO_JEWEL)
+ param.rf_protocol = NCI_RF_PROTOCOL_T1T;
+ else if (protocol == NFC_PROTO_MIFARE)
+ param.rf_protocol = NCI_RF_PROTOCOL_T2T;
+ else if (protocol == NFC_PROTO_FELICA)
+ param.rf_protocol = NCI_RF_PROTOCOL_T3T;
+ else if (protocol == NFC_PROTO_ISO14443)
+ param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
+ else
+ param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
+
+ rc = nci_request(ndev, nci_rf_discover_select_req,
+ (unsigned long)&param,
+ msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT));
+ }
+
+ if (!rc)
+ ndev->target_active_prot = protocol;
+
+ return rc;
}
static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx)
@@ -433,16 +514,15 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx)
ndev->target_active_prot = 0;
- if (test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
+ if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) {
nci_request(ndev, nci_rf_deactivate_req, 0,
- msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
+ msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
}
}
static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx,
- struct sk_buff *skb,
- data_exchange_cb_t cb,
- void *cb_context)
+ struct sk_buff *skb,
+ data_exchange_cb_t cb, void *cb_context)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
int rc;
@@ -487,9 +567,8 @@ static struct nfc_ops nci_nfc_ops = {
* @supported_protocols: NFC protocols supported by the device
*/
struct nci_dev *nci_allocate_device(struct nci_ops *ops,
- __u32 supported_protocols,
- int tx_headroom,
- int tx_tailroom)
+ __u32 supported_protocols,
+ int tx_headroom, int tx_tailroom)
{
struct nci_dev *ndev;
@@ -510,9 +589,9 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops,
ndev->tx_tailroom = tx_tailroom;
ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops,
- supported_protocols,
- tx_headroom + NCI_DATA_HDR_SIZE,
- tx_tailroom);
+ supported_protocols,
+ tx_headroom + NCI_DATA_HDR_SIZE,
+ tx_tailroom);
if (!ndev->nfc_dev)
goto free_exit;
@@ -584,7 +663,9 @@ int nci_register_device(struct nci_dev *ndev)
skb_queue_head_init(&ndev->tx_q);
setup_timer(&ndev->cmd_timer, nci_cmd_timer,
- (unsigned long) ndev);
+ (unsigned long) ndev);
+ setup_timer(&ndev->data_timer, nci_data_timer,
+ (unsigned long) ndev);
mutex_init(&ndev->req_lock);
@@ -633,7 +714,7 @@ int nci_recv_frame(struct sk_buff *skb)
pr_debug("len %d\n", skb->len);
if (!ndev || (!test_bit(NCI_UP, &ndev->flags)
- && !test_bit(NCI_INIT, &ndev->flags))) {
+ && !test_bit(NCI_INIT, &ndev->flags))) {
kfree_skb(skb);
return -ENXIO;
}
@@ -713,7 +794,7 @@ static void nci_tx_work(struct work_struct *work)
/* Check if data flow control is used */
if (atomic_read(&ndev->credits_cnt) !=
- NCI_DATA_FLOW_CONTROL_NOT_USED)
+ NCI_DATA_FLOW_CONTROL_NOT_USED)
atomic_dec(&ndev->credits_cnt);
pr_debug("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d\n",
@@ -722,6 +803,9 @@ static void nci_tx_work(struct work_struct *work)
nci_plen(skb->data));
nci_send_frame(skb);
+
+ mod_timer(&ndev->data_timer,
+ jiffies + msecs_to_jiffies(NCI_DATA_TIMEOUT));
}
}
@@ -753,6 +837,15 @@ static void nci_rx_work(struct work_struct *work)
break;
}
}
+
+ /* check if a data exchange timout has occurred */
+ if (test_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags)) {
+ /* complete the data exchange transaction, if exists */
+ if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+ nci_data_exchange_complete(ndev, NULL, -ETIMEDOUT);
+
+ clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
+ }
}
/* ----- NCI TX CMD worker thread ----- */
@@ -781,6 +874,6 @@ static void nci_cmd_work(struct work_struct *work)
nci_send_frame(skb);
mod_timer(&ndev->cmd_timer,
- jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT));
+ jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT));
}
}
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
index e5756b3..a0bc326 100644
--- a/net/nfc/nci/data.c
+++ b/net/nfc/nci/data.c
@@ -35,8 +35,7 @@
#include <linux/nfc.h>
/* Complete data exchange transaction and forward skb to nfc core */
-void nci_data_exchange_complete(struct nci_dev *ndev,
- struct sk_buff *skb,
+void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
int err)
{
data_exchange_cb_t cb = ndev->data_exchange_cb;
@@ -44,6 +43,10 @@ void nci_data_exchange_complete(struct nci_dev *ndev,
pr_debug("len %d, err %d\n", skb ? skb->len : 0, err);
+ /* data exchange is complete, stop the data timer */
+ del_timer_sync(&ndev->data_timer);
+ clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
+
if (cb) {
ndev->data_exchange_cb = NULL;
ndev->data_exchange_cb_context = 0;
@@ -63,9 +66,9 @@ void nci_data_exchange_complete(struct nci_dev *ndev,
/* ----------------- NCI TX Data ----------------- */
static inline void nci_push_data_hdr(struct nci_dev *ndev,
- __u8 conn_id,
- struct sk_buff *skb,
- __u8 pbf)
+ __u8 conn_id,
+ struct sk_buff *skb,
+ __u8 pbf)
{
struct nci_data_hdr *hdr;
int plen = skb->len;
@@ -82,8 +85,8 @@ static inline void nci_push_data_hdr(struct nci_dev *ndev,
}
static int nci_queue_tx_data_frags(struct nci_dev *ndev,
- __u8 conn_id,
- struct sk_buff *skb) {
+ __u8 conn_id,
+ struct sk_buff *skb) {
int total_len = skb->len;
unsigned char *data = skb->data;
unsigned long flags;
@@ -101,8 +104,8 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
min_t(int, total_len, ndev->max_data_pkt_payload_size);
skb_frag = nci_skb_alloc(ndev,
- (NCI_DATA_HDR_SIZE + frag_len),
- GFP_KERNEL);
+ (NCI_DATA_HDR_SIZE + frag_len),
+ GFP_KERNEL);
if (skb_frag == NULL) {
rc = -ENOMEM;
goto free_exit;
@@ -114,7 +117,8 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
/* second, set the header */
nci_push_data_hdr(ndev, conn_id, skb_frag,
- ((total_len == frag_len) ? (NCI_PBF_LAST) : (NCI_PBF_CONT)));
+ ((total_len == frag_len) ?
+ (NCI_PBF_LAST) : (NCI_PBF_CONT)));
__skb_queue_tail(&frags_q, skb_frag);
@@ -182,8 +186,8 @@ exit:
/* ----------------- NCI RX Data ----------------- */
static void nci_add_rx_data_frag(struct nci_dev *ndev,
- struct sk_buff *skb,
- __u8 pbf)
+ struct sk_buff *skb,
+ __u8 pbf)
{
int reassembly_len;
int err = 0;
@@ -207,8 +211,8 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev,
/* second, combine the two fragments */
memcpy(skb_push(skb, reassembly_len),
- ndev->rx_data_reassembly->data,
- reassembly_len);
+ ndev->rx_data_reassembly->data,
+ reassembly_len);
/* third, free old reassembly */
kfree_skb(ndev->rx_data_reassembly);
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
index b16a8dc..2e3dee4 100644
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -40,7 +40,7 @@
/* Handle NCI Notification packets */
static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
struct nci_core_conn_credit_ntf *ntf = (void *) skb->data;
int i;
@@ -62,7 +62,7 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
if (ntf->conn_entries[i].conn_id == NCI_STATIC_RF_CONN_ID) {
/* found static rf connection */
atomic_add(ntf->conn_entries[i].credits,
- &ndev->credits_cnt);
+ &ndev->credits_cnt);
}
}
@@ -71,6 +71,20 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
queue_work(ndev->tx_wq, &ndev->tx_work);
}
+static void nci_core_generic_error_ntf_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ __u8 status = skb->data[0];
+
+ pr_debug("status 0x%x\n", status);
+
+ if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) {
+ /* Activation failed, so complete the request
+ (the state remains the same) */
+ nci_req_complete(ndev, status);
+ }
+}
+
static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev,
struct sk_buff *skb)
{
@@ -86,12 +100,9 @@ static void nci_core_conn_intf_error_ntf_packet(struct nci_dev *ndev,
}
static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
- struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
+ struct rf_tech_specific_params_nfca_poll *nfca_poll,
+ __u8 *data)
{
- struct rf_tech_specific_params_nfca_poll *nfca_poll;
-
- nfca_poll = &ntf->rf_tech_specific_params.nfca_poll;
-
nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
data += 2;
@@ -115,79 +126,266 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
return data;
}
+static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev,
+ struct rf_tech_specific_params_nfcb_poll *nfcb_poll,
+ __u8 *data)
+{
+ nfcb_poll->sensb_res_len = *data++;
+
+ pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len);
+
+ memcpy(nfcb_poll->sensb_res, data, nfcb_poll->sensb_res_len);
+ data += nfcb_poll->sensb_res_len;
+
+ return data;
+}
+
+static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev,
+ struct rf_tech_specific_params_nfcf_poll *nfcf_poll,
+ __u8 *data)
+{
+ nfcf_poll->bit_rate = *data++;
+ nfcf_poll->sensf_res_len = *data++;
+
+ pr_debug("bit_rate %d, sensf_res_len %d\n",
+ nfcf_poll->bit_rate, nfcf_poll->sensf_res_len);
+
+ memcpy(nfcf_poll->sensf_res, data, nfcf_poll->sensf_res_len);
+ data += nfcf_poll->sensf_res_len;
+
+ return data;
+}
+
+static int nci_add_new_protocol(struct nci_dev *ndev,
+ struct nfc_target *target,
+ __u8 rf_protocol,
+ __u8 rf_tech_and_mode,
+ void *params)
+{
+ struct rf_tech_specific_params_nfca_poll *nfca_poll;
+ struct rf_tech_specific_params_nfcb_poll *nfcb_poll;
+ struct rf_tech_specific_params_nfcf_poll *nfcf_poll;
+ __u32 protocol;
+
+ if (rf_protocol == NCI_RF_PROTOCOL_T2T)
+ protocol = NFC_PROTO_MIFARE_MASK;
+ else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP)
+ protocol = NFC_PROTO_ISO14443_MASK;
+ else if (rf_protocol == NCI_RF_PROTOCOL_T3T)
+ protocol = NFC_PROTO_FELICA_MASK;
+ else
+ protocol = 0;
+
+ if (!(protocol & ndev->poll_prots)) {
+ pr_err("the target found does not have the desired protocol\n");
+ return -EPROTO;
+ }
+
+ if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) {
+ nfca_poll = (struct rf_tech_specific_params_nfca_poll *)params;
+
+ target->sens_res = nfca_poll->sens_res;
+ target->sel_res = nfca_poll->sel_res;
+ target->nfcid1_len = nfca_poll->nfcid1_len;
+ if (target->nfcid1_len > 0) {
+ memcpy(target->nfcid1, nfca_poll->nfcid1,
+ target->nfcid1_len);
+ }
+ } else if (rf_tech_and_mode == NCI_NFC_B_PASSIVE_POLL_MODE) {
+ nfcb_poll = (struct rf_tech_specific_params_nfcb_poll *)params;
+
+ target->sensb_res_len = nfcb_poll->sensb_res_len;
+ if (target->sensb_res_len > 0) {
+ memcpy(target->sensb_res, nfcb_poll->sensb_res,
+ target->sensb_res_len);
+ }
+ } else if (rf_tech_and_mode == NCI_NFC_F_PASSIVE_POLL_MODE) {
+ nfcf_poll = (struct rf_tech_specific_params_nfcf_poll *)params;
+
+ target->sensf_res_len = nfcf_poll->sensf_res_len;
+ if (target->sensf_res_len > 0) {
+ memcpy(target->sensf_res, nfcf_poll->sensf_res,
+ target->sensf_res_len);
+ }
+ } else {
+ pr_err("unsupported rf_tech_and_mode 0x%x\n", rf_tech_and_mode);
+ return -EPROTO;
+ }
+
+ target->supported_protocols |= protocol;
+
+ pr_debug("protocol 0x%x\n", protocol);
+
+ return 0;
+}
+
+static void nci_add_new_target(struct nci_dev *ndev,
+ struct nci_rf_discover_ntf *ntf)
+{
+ struct nfc_target *target;
+ int i, rc;
+
+ for (i = 0; i < ndev->n_targets; i++) {
+ target = &ndev->targets[i];
+ if (target->idx == ntf->rf_discovery_id) {
+ /* This target already exists, add the new protocol */
+ nci_add_new_protocol(ndev, target, ntf->rf_protocol,
+ ntf->rf_tech_and_mode,
+ &ntf->rf_tech_specific_params);
+ return;
+ }
+ }
+
+ /* This is a new target, check if we've enough room */
+ if (ndev->n_targets == NCI_MAX_DISCOVERED_TARGETS) {
+ pr_debug("not enough room, ignoring new target...\n");
+ return;
+ }
+
+ target = &ndev->targets[ndev->n_targets];
+
+ rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol,
+ ntf->rf_tech_and_mode,
+ &ntf->rf_tech_specific_params);
+ if (!rc) {
+ target->idx = ntf->rf_discovery_id;
+ ndev->n_targets++;
+
+ pr_debug("target_idx %d, n_targets %d\n", target->idx,
+ ndev->n_targets);
+ }
+}
+
+void nci_clear_target_list(struct nci_dev *ndev)
+{
+ memset(ndev->targets, 0,
+ (sizeof(struct nfc_target)*NCI_MAX_DISCOVERED_TARGETS));
+
+ ndev->n_targets = 0;
+}
+
+static void nci_rf_discover_ntf_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ struct nci_rf_discover_ntf ntf;
+ __u8 *data = skb->data;
+ bool add_target = true;
+
+ ntf.rf_discovery_id = *data++;
+ ntf.rf_protocol = *data++;
+ ntf.rf_tech_and_mode = *data++;
+ ntf.rf_tech_specific_params_len = *data++;
+
+ pr_debug("rf_discovery_id %d\n", ntf.rf_discovery_id);
+ pr_debug("rf_protocol 0x%x\n", ntf.rf_protocol);
+ pr_debug("rf_tech_and_mode 0x%x\n", ntf.rf_tech_and_mode);
+ pr_debug("rf_tech_specific_params_len %d\n",
+ ntf.rf_tech_specific_params_len);
+
+ if (ntf.rf_tech_specific_params_len > 0) {
+ switch (ntf.rf_tech_and_mode) {
+ case NCI_NFC_A_PASSIVE_POLL_MODE:
+ data = nci_extract_rf_params_nfca_passive_poll(ndev,
+ &(ntf.rf_tech_specific_params.nfca_poll), data);
+ break;
+
+ case NCI_NFC_B_PASSIVE_POLL_MODE:
+ data = nci_extract_rf_params_nfcb_passive_poll(ndev,
+ &(ntf.rf_tech_specific_params.nfcb_poll), data);
+ break;
+
+ case NCI_NFC_F_PASSIVE_POLL_MODE:
+ data = nci_extract_rf_params_nfcf_passive_poll(ndev,
+ &(ntf.rf_tech_specific_params.nfcf_poll), data);
+ break;
+
+ default:
+ pr_err("unsupported rf_tech_and_mode 0x%x\n",
+ ntf.rf_tech_and_mode);
+ data += ntf.rf_tech_specific_params_len;
+ add_target = false;
+ }
+ }
+
+ ntf.ntf_type = *data++;
+ pr_debug("ntf_type %d\n", ntf.ntf_type);
+
+ if (add_target == true)
+ nci_add_new_target(ndev, &ntf);
+
+ if (ntf.ntf_type == NCI_DISCOVER_NTF_TYPE_MORE) {
+ atomic_set(&ndev->state, NCI_W4_ALL_DISCOVERIES);
+ } else {
+ atomic_set(&ndev->state, NCI_W4_HOST_SELECT);
+ nfc_targets_found(ndev->nfc_dev, ndev->targets,
+ ndev->n_targets);
+ }
+}
+
static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
{
struct activation_params_nfca_poll_iso_dep *nfca_poll;
+ struct activation_params_nfcb_poll_iso_dep *nfcb_poll;
switch (ntf->activation_rf_tech_and_mode) {
case NCI_NFC_A_PASSIVE_POLL_MODE:
nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
nfca_poll->rats_res_len = *data++;
+ pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len);
if (nfca_poll->rats_res_len > 0) {
memcpy(nfca_poll->rats_res,
- data,
- nfca_poll->rats_res_len);
+ data, nfca_poll->rats_res_len);
+ }
+ break;
+
+ case NCI_NFC_B_PASSIVE_POLL_MODE:
+ nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep;
+ nfcb_poll->attrib_res_len = *data++;
+ pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len);
+ if (nfcb_poll->attrib_res_len > 0) {
+ memcpy(nfcb_poll->attrib_res,
+ data, nfcb_poll->attrib_res_len);
}
break;
default:
pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
ntf->activation_rf_tech_and_mode);
- return -EPROTO;
+ return NCI_STATUS_RF_PROTOCOL_ERROR;
}
- return 0;
+ return NCI_STATUS_OK;
}
-static void nci_target_found(struct nci_dev *ndev,
- struct nci_rf_intf_activated_ntf *ntf)
+static void nci_target_auto_activated(struct nci_dev *ndev,
+ struct nci_rf_intf_activated_ntf *ntf)
{
- struct nfc_target nfc_tgt;
+ struct nfc_target *target;
+ int rc;
- if (ntf->rf_protocol == NCI_RF_PROTOCOL_T2T) /* T2T MifareUL */
- nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK;
- else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) /* 4A */
- nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK;
- else
- nfc_tgt.supported_protocols = 0;
-
- nfc_tgt.sens_res = ntf->rf_tech_specific_params.nfca_poll.sens_res;
- nfc_tgt.sel_res = ntf->rf_tech_specific_params.nfca_poll.sel_res;
- nfc_tgt.nfcid1_len = ntf->rf_tech_specific_params.nfca_poll.nfcid1_len;
- if (nfc_tgt.nfcid1_len > 0) {
- memcpy(nfc_tgt.nfcid1,
- ntf->rf_tech_specific_params.nfca_poll.nfcid1,
- nfc_tgt.nfcid1_len);
- }
+ target = &ndev->targets[ndev->n_targets];
- if (!(nfc_tgt.supported_protocols & ndev->poll_prots)) {
- pr_debug("the target found does not have the desired protocol\n");
+ rc = nci_add_new_protocol(ndev, target, ntf->rf_protocol,
+ ntf->activation_rf_tech_and_mode,
+ &ntf->rf_tech_specific_params);
+ if (rc)
return;
- }
- pr_debug("new target found, supported_protocols 0x%x\n",
- nfc_tgt.supported_protocols);
+ target->idx = ntf->rf_discovery_id;
+ ndev->n_targets++;
- ndev->target_available_prots = nfc_tgt.supported_protocols;
- ndev->max_data_pkt_payload_size = ntf->max_data_pkt_payload_size;
- ndev->initial_num_credits = ntf->initial_num_credits;
+ pr_debug("target_idx %d, n_targets %d\n", target->idx, ndev->n_targets);
- /* set the available credits to initial value */
- atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
-
- nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1);
+ nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets);
}
static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
struct nci_rf_intf_activated_ntf ntf;
__u8 *data = skb->data;
- int err = 0;
-
- clear_bit(NCI_DISCOVERY, &ndev->flags);
- set_bit(NCI_POLL_ACTIVE, &ndev->flags);
+ int err = NCI_STATUS_OK;
ntf.rf_discovery_id = *data++;
ntf.rf_interface = *data++;
@@ -204,7 +402,8 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
ntf.activation_rf_tech_and_mode);
pr_debug("max_data_pkt_payload_size 0x%x\n",
ntf.max_data_pkt_payload_size);
- pr_debug("initial_num_credits 0x%x\n", ntf.initial_num_credits);
+ pr_debug("initial_num_credits 0x%x\n",
+ ntf.initial_num_credits);
pr_debug("rf_tech_specific_params_len %d\n",
ntf.rf_tech_specific_params_len);
@@ -212,13 +411,24 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
switch (ntf.activation_rf_tech_and_mode) {
case NCI_NFC_A_PASSIVE_POLL_MODE:
data = nci_extract_rf_params_nfca_passive_poll(ndev,
- &ntf, data);
+ &(ntf.rf_tech_specific_params.nfca_poll), data);
+ break;
+
+ case NCI_NFC_B_PASSIVE_POLL_MODE:
+ data = nci_extract_rf_params_nfcb_passive_poll(ndev,
+ &(ntf.rf_tech_specific_params.nfcb_poll), data);
+ break;
+
+ case NCI_NFC_F_PASSIVE_POLL_MODE:
+ data = nci_extract_rf_params_nfcf_passive_poll(ndev,
+ &(ntf.rf_tech_specific_params.nfcf_poll), data);
break;
default:
pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
ntf.activation_rf_tech_and_mode);
- return;
+ err = NCI_STATUS_RF_PROTOCOL_ERROR;
+ goto exit;
}
}
@@ -229,18 +439,15 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
pr_debug("data_exch_rf_tech_and_mode 0x%x\n",
ntf.data_exch_rf_tech_and_mode);
- pr_debug("data_exch_tx_bit_rate 0x%x\n",
- ntf.data_exch_tx_bit_rate);
- pr_debug("data_exch_rx_bit_rate 0x%x\n",
- ntf.data_exch_rx_bit_rate);
- pr_debug("activation_params_len %d\n",
- ntf.activation_params_len);
+ pr_debug("data_exch_tx_bit_rate 0x%x\n", ntf.data_exch_tx_bit_rate);
+ pr_debug("data_exch_rx_bit_rate 0x%x\n", ntf.data_exch_rx_bit_rate);
+ pr_debug("activation_params_len %d\n", ntf.activation_params_len);
if (ntf.activation_params_len > 0) {
switch (ntf.rf_interface) {
case NCI_RF_INTERFACE_ISO_DEP:
err = nci_extract_activation_params_iso_dep(ndev,
- &ntf, data);
+ &ntf, data);
break;
case NCI_RF_INTERFACE_FRAME:
@@ -250,24 +457,39 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
default:
pr_err("unsupported rf_interface 0x%x\n",
ntf.rf_interface);
- return;
+ err = NCI_STATUS_RF_PROTOCOL_ERROR;
+ break;
}
}
- if (!err)
- nci_target_found(ndev, &ntf);
+exit:
+ if (err == NCI_STATUS_OK) {
+ ndev->max_data_pkt_payload_size = ntf.max_data_pkt_payload_size;
+ ndev->initial_num_credits = ntf.initial_num_credits;
+
+ /* set the available credits to initial value */
+ atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
+ }
+
+ if (atomic_read(&ndev->state) == NCI_DISCOVERY) {
+ /* A single target was found and activated automatically */
+ atomic_set(&ndev->state, NCI_POLL_ACTIVE);
+ if (err == NCI_STATUS_OK)
+ nci_target_auto_activated(ndev, &ntf);
+ } else { /* ndev->state == NCI_W4_HOST_SELECT */
+ /* A selected target was activated, so complete the request */
+ atomic_set(&ndev->state, NCI_POLL_ACTIVE);
+ nci_req_complete(ndev, err);
+ }
}
static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
struct nci_rf_deactivate_ntf *ntf = (void *) skb->data;
pr_debug("entry, type 0x%x, reason 0x%x\n", ntf->type, ntf->reason);
- clear_bit(NCI_POLL_ACTIVE, &ndev->flags);
- ndev->target_active_prot = 0;
-
/* drop tx data queue */
skb_queue_purge(&ndev->tx_q);
@@ -280,6 +502,10 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
/* complete the data exchange transaction, if exists */
if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
nci_data_exchange_complete(ndev, NULL, -EIO);
+
+ nci_clear_target_list(ndev);
+ atomic_set(&ndev->state, NCI_IDLE);
+ nci_req_complete(ndev, NCI_STATUS_OK);
}
void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
@@ -300,10 +526,18 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
nci_core_conn_credits_ntf_packet(ndev, skb);
break;
+ case NCI_OP_CORE_GENERIC_ERROR_NTF:
+ nci_core_generic_error_ntf_packet(ndev, skb);
+ break;
+
case NCI_OP_CORE_INTF_ERROR_NTF:
nci_core_conn_intf_error_ntf_packet(ndev, skb);
break;
+ case NCI_OP_RF_DISCOVER_NTF:
+ nci_rf_discover_ntf_packet(ndev, skb);
+ break;
+
case NCI_OP_RF_INTF_ACTIVATED_NTF:
nci_rf_intf_activated_ntf_packet(ndev, skb);
break;
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c
index 2840ae2..3003c33 100644
--- a/net/nfc/nci/rsp.c
+++ b/net/nfc/nci/rsp.c
@@ -67,19 +67,18 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces;
if (ndev->num_supported_rf_interfaces >
- NCI_MAX_SUPPORTED_RF_INTERFACES) {
+ NCI_MAX_SUPPORTED_RF_INTERFACES) {
ndev->num_supported_rf_interfaces =
NCI_MAX_SUPPORTED_RF_INTERFACES;
}
memcpy(ndev->supported_rf_interfaces,
- rsp_1->supported_rf_interfaces,
- ndev->num_supported_rf_interfaces);
+ rsp_1->supported_rf_interfaces,
+ ndev->num_supported_rf_interfaces);
rsp_2 = (void *) (skb->data + 6 + rsp_1->num_supported_rf_interfaces);
- ndev->max_logical_connections =
- rsp_2->max_logical_connections;
+ ndev->max_logical_connections = rsp_2->max_logical_connections;
ndev->max_routing_table_size =
__le16_to_cpu(rsp_2->max_routing_table_size);
ndev->max_ctrl_pkt_payload_len =
@@ -121,7 +120,7 @@ exit:
}
static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev,
- struct sk_buff *skb)
+ struct sk_buff *skb)
{
__u8 status = skb->data[0];
@@ -137,21 +136,37 @@ static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
pr_debug("status 0x%x\n", status);
if (status == NCI_STATUS_OK)
- set_bit(NCI_DISCOVERY, &ndev->flags);
+ atomic_set(&ndev->state, NCI_DISCOVERY);
nci_req_complete(ndev, status);
}
-static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev,
- struct sk_buff *skb)
+static void nci_rf_disc_select_rsp_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
{
__u8 status = skb->data[0];
pr_debug("status 0x%x\n", status);
- clear_bit(NCI_DISCOVERY, &ndev->flags);
+ /* Complete the request on intf_activated_ntf or generic_error_ntf */
+ if (status != NCI_STATUS_OK)
+ nci_req_complete(ndev, status);
+}
- nci_req_complete(ndev, status);
+static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev,
+ struct sk_buff *skb)
+{
+ __u8 status = skb->data[0];
+
+ pr_debug("status 0x%x\n", status);
+
+ /* If target was active, complete the request only in deactivate_ntf */
+ if ((status != NCI_STATUS_OK) ||
+ (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
+ nci_clear_target_list(ndev);
+ atomic_set(&ndev->state, NCI_IDLE);
+ nci_req_complete(ndev, status);
+ }
}
void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
@@ -187,6 +202,10 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
nci_rf_disc_rsp_packet(ndev, skb);
break;
+ case NCI_OP_RF_DISCOVER_SELECT_RSP:
+ nci_rf_disc_select_rsp_packet(ndev, skb);
+ break;
+
case NCI_OP_RF_DEACTIVATE_RSP:
nci_rf_deactivate_rsp_packet(ndev, skb);
break;
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index 6989dfa..6404052 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -48,28 +48,34 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
[NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 },
[NFC_ATTR_COMM_MODE] = { .type = NLA_U8 },
[NFC_ATTR_RF_MODE] = { .type = NLA_U8 },
+ [NFC_ATTR_DEVICE_POWERED] = { .type = NLA_U8 },
};
static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
- struct netlink_callback *cb, int flags)
+ struct netlink_callback *cb, int flags)
{
void *hdr;
hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
- &nfc_genl_family, flags, NFC_CMD_GET_TARGET);
+ &nfc_genl_family, flags, NFC_CMD_GET_TARGET);
if (!hdr)
return -EMSGSIZE;
genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
NLA_PUT_U32(msg, NFC_ATTR_TARGET_INDEX, target->idx);
- NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS,
- target->supported_protocols);
+ NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, target->supported_protocols);
NLA_PUT_U16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res);
NLA_PUT_U8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res);
if (target->nfcid1_len > 0)
NLA_PUT(msg, NFC_ATTR_TARGET_NFCID1, target->nfcid1_len,
- target->nfcid1);
+ target->nfcid1);
+ if (target->sensb_res_len > 0)
+ NLA_PUT(msg, NFC_ATTR_TARGET_SENSB_RES, target->sensb_res_len,
+ target->sensb_res);
+ if (target->sensf_res_len > 0)
+ NLA_PUT(msg, NFC_ATTR_TARGET_SENSF_RES, target->sensf_res_len,
+ target->sensf_res);
return genlmsg_end(msg, hdr);
@@ -85,9 +91,9 @@ static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
u32 idx;
rc = nlmsg_parse(cb->nlh, GENL_HDRLEN + nfc_genl_family.hdrsize,
- nfc_genl_family.attrbuf,
- nfc_genl_family.maxattr,
- nfc_genl_policy);
+ nfc_genl_family.attrbuf,
+ nfc_genl_family.maxattr,
+ nfc_genl_policy);
if (rc < 0)
return ERR_PTR(rc);
@@ -104,7 +110,7 @@ static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
}
static int nfc_genl_dump_targets(struct sk_buff *skb,
- struct netlink_callback *cb)
+ struct netlink_callback *cb)
{
int i = cb->args[0];
struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
@@ -124,7 +130,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb,
while (i < dev->n_targets) {
rc = nfc_genl_send_target(skb, &dev->targets[i], cb,
- NLM_F_MULTI);
+ NLM_F_MULTI);
if (rc < 0)
break;
@@ -160,7 +166,7 @@ int nfc_genl_targets_found(struct nfc_dev *dev)
return -ENOMEM;
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
- NFC_EVENT_TARGETS_FOUND);
+ NFC_EVENT_TARGETS_FOUND);
if (!hdr)
goto free_msg;
@@ -187,13 +193,14 @@ int nfc_genl_device_added(struct nfc_dev *dev)
return -ENOMEM;
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
- NFC_EVENT_DEVICE_ADDED);
+ NFC_EVENT_DEVICE_ADDED);
if (!hdr)
goto free_msg;
NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev));
NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols);
+ NLA_PUT_U8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up);
genlmsg_end(msg, hdr);
@@ -218,7 +225,7 @@ int nfc_genl_device_removed(struct nfc_dev *dev)
return -ENOMEM;
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
- NFC_EVENT_DEVICE_REMOVED);
+ NFC_EVENT_DEVICE_REMOVED);
if (!hdr)
goto free_msg;
@@ -238,14 +245,14 @@ free_msg:
}
static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
- u32 pid, u32 seq,
- struct netlink_callback *cb,
- int flags)
+ u32 pid, u32 seq,
+ struct netlink_callback *cb,
+ int flags)
{
void *hdr;
hdr = genlmsg_put(msg, pid, seq, &nfc_genl_family, flags,
- NFC_CMD_GET_DEVICE);
+ NFC_CMD_GET_DEVICE);
if (!hdr)
return -EMSGSIZE;
@@ -255,6 +262,7 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev));
NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols);
+ NLA_PUT_U8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up);
return genlmsg_end(msg, hdr);
@@ -264,7 +272,7 @@ nla_put_failure:
}
static int nfc_genl_dump_devices(struct sk_buff *skb,
- struct netlink_callback *cb)
+ struct netlink_callback *cb)
{
struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
@@ -291,8 +299,7 @@ static int nfc_genl_dump_devices(struct sk_buff *skb,
int rc;
rc = nfc_genl_send_device(skb, dev, NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq,
- cb, NLM_F_MULTI);
+ cb->nlh->nlmsg_seq, cb, NLM_F_MULTI);
if (rc < 0)
break;
@@ -317,7 +324,7 @@ static int nfc_genl_dump_devices_done(struct netlink_callback *cb)
}
int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
- u8 comm_mode, u8 rf_mode)
+ u8 comm_mode, u8 rf_mode)
{
struct sk_buff *msg;
void *hdr;
@@ -328,8 +335,7 @@ int nfc_genl_dep_link_up_event(struct nfc_dev *dev, u32 target_idx,
if (!msg)
return -ENOMEM;
- hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
- NFC_CMD_DEP_LINK_UP);
+ hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, NFC_CMD_DEP_LINK_UP);
if (!hdr)
goto free_msg;
@@ -366,7 +372,7 @@ int nfc_genl_dep_link_down_event(struct nfc_dev *dev)
return -ENOMEM;
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
- NFC_CMD_DEP_LINK_DOWN);
+ NFC_CMD_DEP_LINK_DOWN);
if (!hdr)
goto free_msg;
@@ -408,7 +414,7 @@ static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info)
}
rc = nfc_genl_send_device(msg, dev, info->snd_pid, info->snd_seq,
- NULL, 0);
+ NULL, 0);
if (rc < 0)
goto out_free;
@@ -475,7 +481,7 @@ static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
pr_debug("Poll start\n");
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
- !info->attrs[NFC_ATTR_PROTOCOLS])
+ !info->attrs[NFC_ATTR_PROTOCOLS])
return -EINVAL;
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
@@ -533,13 +539,12 @@ static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info)
struct nfc_dev *dev;
int rc, tgt_idx;
u32 idx;
- u8 comm, rf;
+ u8 comm;
pr_debug("DEP link up\n");
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
- !info->attrs[NFC_ATTR_COMM_MODE] ||
- !info->attrs[NFC_ATTR_RF_MODE])
+ !info->attrs[NFC_ATTR_COMM_MODE])
return -EINVAL;
idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
@@ -549,19 +554,15 @@ static int nfc_genl_dep_link_up(struct sk_buff *skb, struct genl_info *info)
tgt_idx = nla_get_u32(info->attrs[NFC_ATTR_TARGET_INDEX]);
comm = nla_get_u8(info->attrs[NFC_ATTR_COMM_MODE]);
- rf = nla_get_u8(info->attrs[NFC_ATTR_RF_MODE]);
if (comm != NFC_COMM_ACTIVE && comm != NFC_COMM_PASSIVE)
return -EINVAL;
- if (rf != NFC_RF_INITIATOR && comm != NFC_RF_TARGET)
- return -EINVAL;
-
dev = nfc_get_device(idx);
if (!dev)
return -ENODEV;
- rc = nfc_dep_link_up(dev, tgt_idx, comm, rf);
+ rc = nfc_dep_link_up(dev, tgt_idx, comm);
nfc_put_device(dev);
@@ -636,7 +637,7 @@ static struct genl_ops nfc_genl_ops[] = {
};
static int nfc_genl_rcv_nl_event(struct notifier_block *this,
- unsigned long event, void *ptr)
+ unsigned long event, void *ptr)
{
struct netlink_notify *n = ptr;
struct class_dev_iter iter;
@@ -689,7 +690,7 @@ int __init nfc_genl_init(void)
int rc;
rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops,
- ARRAY_SIZE(nfc_genl_ops));
+ ARRAY_SIZE(nfc_genl_ops));
if (rc)
return rc;
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index 6d28d75..ec8794c 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -32,7 +32,7 @@ struct nfc_protocol {
struct proto *proto;
struct module *owner;
int (*create)(struct net *net, struct socket *sock,
- const struct nfc_protocol *nfc_proto);
+ const struct nfc_protocol *nfc_proto);
};
struct nfc_rawsock {
@@ -54,7 +54,7 @@ void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx,
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, u8 *general_bytes_len);
+u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len);
int __init nfc_llcp_init(void);
void nfc_llcp_exit(void);
@@ -65,7 +65,7 @@ static inline void nfc_llcp_mac_is_down(struct nfc_dev *dev)
}
static inline void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx,
- u8 comm_mode, u8 rf_mode)
+ u8 comm_mode, u8 rf_mode)
{
}
@@ -78,7 +78,8 @@ static inline void nfc_llcp_unregister_device(struct nfc_dev *dev)
{
}
-static inline int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len)
+static inline int nfc_llcp_set_remote_gb(struct nfc_dev *dev,
+ u8 *gb, u8 gb_len)
{
return 0;
}
@@ -160,8 +161,7 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols);
int nfc_stop_poll(struct nfc_dev *dev);
-int nfc_dep_link_up(struct nfc_dev *dev, int target_idx,
- u8 comm_mode, u8 rf_mode);
+int nfc_dep_link_up(struct nfc_dev *dev, int target_idx, u8 comm_mode);
int nfc_dep_link_down(struct nfc_dev *dev);
@@ -169,9 +169,7 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol);
int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx);
-int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx,
- struct sk_buff *skb,
- data_exchange_cb_t cb,
- void *cb_context);
+int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
+ data_exchange_cb_t cb, void *cb_context);
#endif /* __LOCAL_NFC_H */
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
index 2e2f8c6..5a839ce 100644
--- a/net/nfc/rawsock.c
+++ b/net/nfc/rawsock.c
@@ -63,7 +63,7 @@ static int rawsock_release(struct socket *sock)
}
static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
- int len, int flags)
+ int len, int flags)
{
struct sock *sk = sock->sk;
struct sockaddr_nfc *addr = (struct sockaddr_nfc *)_addr;
@@ -73,7 +73,7 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
pr_debug("sock=%p sk=%p flags=%d\n", sock, sk, flags);
if (!addr || len < sizeof(struct sockaddr_nfc) ||
- addr->sa_family != AF_NFC)
+ addr->sa_family != AF_NFC)
return -EINVAL;
pr_debug("addr dev_idx=%u target_idx=%u protocol=%u\n",
@@ -92,18 +92,6 @@ static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
goto error;
}
- if (addr->target_idx > dev->target_idx - 1 ||
- addr->target_idx < dev->target_idx - dev->n_targets) {
- rc = -EINVAL;
- goto error;
- }
-
- if (addr->target_idx > dev->target_idx - 1 ||
- addr->target_idx < dev->target_idx - dev->n_targets) {
- rc = -EINVAL;
- goto error;
- }
-
rc = nfc_activate_target(dev, addr->target_idx, addr->nfc_protocol);
if (rc)
goto put_dev;
@@ -132,7 +120,7 @@ static int rawsock_add_header(struct sk_buff *skb)
}
static void rawsock_data_exchange_complete(void *context, struct sk_buff *skb,
- int err)
+ int err)
{
struct sock *sk = (struct sock *) context;
@@ -185,7 +173,7 @@ static void rawsock_tx_work(struct work_struct *work)
sock_hold(sk);
rc = nfc_data_exchange(dev, target_idx, skb,
- rawsock_data_exchange_complete, sk);
+ rawsock_data_exchange_complete, sk);
if (rc) {
rawsock_report_error(sk, rc);
sock_put(sk);
@@ -193,7 +181,7 @@ static void rawsock_tx_work(struct work_struct *work)
}
static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len)
+ struct msghdr *msg, size_t len)
{
struct sock *sk = sock->sk;
struct nfc_dev *dev = nfc_rawsock(sk)->dev;
@@ -230,7 +218,7 @@ static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
}
static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
- struct msghdr *msg, size_t len, int flags)
+ struct msghdr *msg, size_t len, int flags)
{
int noblock = flags & MSG_DONTWAIT;
struct sock *sk = sock->sk;
@@ -286,7 +274,7 @@ static void rawsock_destruct(struct sock *sk)
if (sk->sk_state == TCP_ESTABLISHED) {
nfc_deactivate_target(nfc_rawsock(sk)->dev,
- nfc_rawsock(sk)->target_idx);
+ nfc_rawsock(sk)->target_idx);
nfc_put_device(nfc_rawsock(sk)->dev);
}
@@ -299,7 +287,7 @@ static void rawsock_destruct(struct sock *sk)
}
static int rawsock_create(struct net *net, struct socket *sock,
- const struct nfc_protocol *nfc_proto)
+ const struct nfc_protocol *nfc_proto)
{
struct sock *sk;
OpenPOWER on IntegriCloud