diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/nfc/core.c | 119 | ||||
-rw-r--r-- | net/nfc/hci/core.c | 13 | ||||
-rw-r--r-- | net/nfc/hci/shdlc.c | 6 | ||||
-rw-r--r-- | net/nfc/llcp/commands.c | 54 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.c | 421 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.h | 26 | ||||
-rw-r--r-- | net/nfc/llcp/sock.c | 47 | ||||
-rw-r--r-- | net/nfc/nci/core.c | 15 | ||||
-rw-r--r-- | net/nfc/netlink.c | 81 | ||||
-rw-r--r-- | net/nfc/nfc.h | 12 |
10 files changed, 530 insertions, 264 deletions
diff --git a/net/nfc/core.c b/net/nfc/core.c index 9f6ce011d35..4177bb5104b 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,9 +143,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 protocols) goto error; } - rc = dev->ops->start_poll(dev, protocols); - if (!rc) + rc = dev->ops->start_poll(dev, im_protocols, tm_protocols); + 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,11 +268,6 @@ int nfc_dep_link_down(struct nfc_dev *dev) goto error; } - if (dev->dep_rf_mode == NFC_RF_TARGET) { - rc = -EOPNOTSUPP; - goto error; - } - rc = dev->ops->dep_link_down(dev); if (!rc) { dev->dep_link_up = false; @@ -286,7 +285,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 +328,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 + @@ -409,27 +408,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); @@ -447,6 +449,63 @@ 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); + +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) +{ + 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; + } + + 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); + + 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 * @@ -678,7 +737,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 e1a640d2b58..a8b0b71e8f8 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); @@ -511,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; @@ -579,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/hci/shdlc.c b/net/nfc/hci/shdlc.c index 5665dc6d893..6b836e6242b 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/llcp/commands.c b/net/nfc/llcp/commands.c index bf8ae4f0b90..b982b5b890d 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) @@ -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,45 @@ 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_MIUX: + sock->miu = llcp_tlv_miux(tlv) + 128; + break; 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 +200,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 miu %d\n", sock, sock->rw, sock->miu); return 0; } @@ -474,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 42994fac26d..5d503eeb15a 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -31,47 +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); - - if (sk->sk_state == LLCP_CONNECTED) - nfc_put_device(s->dev); + write_lock(&l->lock); + sk_add_node(sk, &l->head); + write_unlock(&l->lock); +} - sk->sk_state = LLCP_CLOSED; +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); +} - release_sock(sk); +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; - sock_orphan(sk); + write_lock(&local->sockets.lock); - s->local = NULL; - } + 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); @@ -83,24 +77,53 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) release_sock(accept_sk); sock_orphan(accept_sk); - - lsk->local = NULL; } } - if (parent_sk->sk_state == LLCP_CONNECTED) - nfc_put_device(parent->dev); - - parent_sk->sk_state = LLCP_CLOSED; + sk->sk_state = LLCP_CLOSED; - release_sock(parent_sk); + release_sock(sk); - sock_orphan(parent_sk); + sock_orphan(sk); - parent->local = NULL; + 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) +{ + 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); + destroy_workqueue(local->timeout_wq); + kfree_skb(local->rx_pending); + kfree(local); +} + +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); } static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local) @@ -384,31 +407,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); -} - -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)); + return nfc_llcp_parse_gb_tlv(local, + &local->remote_gb[3], + local->remote_gb_len - 3); } static u8 nfc_llcp_dsap(struct sk_buff *pdu) @@ -443,46 +444,146 @@ 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) +{ + 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) { + sock_hold(&llcp_sock->sk); + goto out; + } + } + + llcp_sock = NULL; + +out: + read_unlock(&local->connecting_sockets.lock); + + 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); - pr_debug("root dsap %d (%d)\n", sock->dsap, dsap); + llcp_sock = NULL; - if (sock->dsap == dsap) { - sock_hold(&sock->sk); - mutex_unlock(&local->socket_lock); - return sock; + sk_for_each(sk, node, &local->sockets.head) { + llcp_sock = nfc_llcp_sock(sk); + + 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) @@ -518,35 +619,19 @@ 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); 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) { - 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; @@ -559,40 +644,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)) { @@ -612,15 +672,19 @@ 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->miu = local->remote_miu; 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; + 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); - list_add_tail(&new_sock->list, &sock->list); + nfc_llcp_sock_link(&local->sockets, new_sk); nfc_llcp_accept_enqueue(&sock->sk, new_sk); @@ -654,12 +718,12 @@ 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) { - struct sk_buff *pdu, *pending_pdu; + skb_queue_len(&sock->tx_pending_queue) < sock->rw) { + struct sk_buff *pdu; pdu = skb_dequeue(&sock->tx_queue); if (pdu == NULL) @@ -668,10 +732,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++; } @@ -728,11 +789,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) @@ -740,7 +811,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); @@ -791,11 +862,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); @@ -803,11 +870,15 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) return; } - llcp_sock->dsap = ssap; sk = &llcp_sock->sk; - nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE], - skb->len - LLCP_HEADER_SIZE); + /* 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_connection_tlv(llcp_sock, &skb->data[LLCP_HEADER_SIZE], + skb->len - LLCP_HEADER_SIZE); sk->sk_state = LLCP_CONNECTED; sk->sk_state_change(sk); @@ -891,6 +962,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; @@ -943,8 +1029,8 @@ 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); local->link_timer.data = (unsigned long) local; local->link_timer.function = nfc_llcp_symm_timer; @@ -984,11 +1070,13 @@ 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; local->remote_lto = LLCP_DEFAULT_LTO; - local->remote_rw = LLCP_DEFAULT_RW; list_add(&llcp_devices, &local->list); @@ -1015,14 +1103,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 50680ce5ae4..7286c86982f 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -40,12 +40,18 @@ 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; + struct kref ref; + struct mutex sdp_lock; - struct mutex socket_lock; struct timer_list link_timer; struct sk_buff_head tx_queue; @@ -77,24 +83,26 @@ struct nfc_llcp_local { u16 remote_lto; u8 remote_opt; u16 remote_wks; - 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; u32 nfc_protocol; + /* Link parameters */ u8 ssap; u8 dsap; char *service_name; size_t service_name_len; + u8 rw; + u16 miu; /* Link variables */ u8 send_n; @@ -164,7 +172,11 @@ 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); 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); @@ -179,8 +191,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 3f339b19d14..30e3cc71be7 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, @@ -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); @@ -487,7 +476,8 @@ 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->miu = llcp_sock->local->remote_miu; llcp_sock->ssap = nfc_llcp_get_local_ssap(local); if (llcp_sock->ssap == LLCP_SAP_MAX) { ret = -ENOMEM; @@ -505,21 +495,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); @@ -684,13 +679,14 @@ 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; 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) @@ -701,8 +697,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); @@ -711,12 +705,9 @@ 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; + + nfc_llcp_local_put(sock->local); } static int llcp_sock_create(struct net *net, struct socket *sock, diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index d560e6f1307..766a02b1dfa 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; } @@ -521,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; @@ -556,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 ---- */ diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 581d419083a..03c31db38f1 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, @@ -219,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; @@ -519,16 +583,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]); + + 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) @@ -536,7 +609,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 3dd4232ae66..c5e42b79a41 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; @@ -128,6 +135,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) @@ -158,7 +168,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); |