diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-04-24 10:54:20 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-04-24 10:54:20 -0400 |
commit | 6ed0e321a0aef14a894e26658108bf7e895c36a6 (patch) | |
tree | f49428d68ebcb1beb757296ea1559079210babbe /net/nfc | |
parent | 3dec2246c2ff11beb24ca1950f074b2bcbc85953 (diff) | |
parent | b006ed545cbadf1ebd4683719554742d20dbcede (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/core.c | 43 | ||||
-rw-r--r-- | net/nfc/llcp/commands.c | 30 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.c | 127 | ||||
-rw-r--r-- | net/nfc/llcp/llcp.h | 5 | ||||
-rw-r--r-- | net/nfc/llcp/sock.c | 43 |
5 files changed, 194 insertions, 54 deletions
diff --git a/net/nfc/core.c b/net/nfc/core.c index 6ceee8e181ca..40d2527693da 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/kernel.h> | 27 | #include <linux/kernel.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/rfkill.h> | ||
30 | #include <linux/nfc.h> | 31 | #include <linux/nfc.h> |
31 | 32 | ||
32 | #include <net/genetlink.h> | 33 | #include <net/genetlink.h> |
@@ -58,6 +59,11 @@ int nfc_dev_up(struct nfc_dev *dev) | |||
58 | 59 | ||
59 | device_lock(&dev->dev); | 60 | device_lock(&dev->dev); |
60 | 61 | ||
62 | if (dev->rfkill && rfkill_blocked(dev->rfkill)) { | ||
63 | rc = -ERFKILL; | ||
64 | goto error; | ||
65 | } | ||
66 | |||
61 | if (!device_is_registered(&dev->dev)) { | 67 | if (!device_is_registered(&dev->dev)) { |
62 | rc = -ENODEV; | 68 | rc = -ENODEV; |
63 | goto error; | 69 | goto error; |
@@ -117,6 +123,24 @@ error: | |||
117 | return rc; | 123 | return rc; |
118 | } | 124 | } |
119 | 125 | ||
126 | static int nfc_rfkill_set_block(void *data, bool blocked) | ||
127 | { | ||
128 | struct nfc_dev *dev = data; | ||
129 | |||
130 | pr_debug("%s blocked %d", dev_name(&dev->dev), blocked); | ||
131 | |||
132 | if (!blocked) | ||
133 | return 0; | ||
134 | |||
135 | nfc_dev_down(dev); | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static const struct rfkill_ops nfc_rfkill_ops = { | ||
141 | .set_block = nfc_rfkill_set_block, | ||
142 | }; | ||
143 | |||
120 | /** | 144 | /** |
121 | * nfc_start_poll - start polling for nfc targets | 145 | * nfc_start_poll - start polling for nfc targets |
122 | * | 146 | * |
@@ -143,6 +167,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols) | |||
143 | goto error; | 167 | goto error; |
144 | } | 168 | } |
145 | 169 | ||
170 | if (!dev->dev_up) { | ||
171 | rc = -ENODEV; | ||
172 | goto error; | ||
173 | } | ||
174 | |||
146 | if (dev->polling) { | 175 | if (dev->polling) { |
147 | rc = -EBUSY; | 176 | rc = -EBUSY; |
148 | goto error; | 177 | goto error; |
@@ -835,6 +864,15 @@ int nfc_register_device(struct nfc_dev *dev) | |||
835 | pr_debug("The userspace won't be notified that the device %s was added\n", | 864 | pr_debug("The userspace won't be notified that the device %s was added\n", |
836 | dev_name(&dev->dev)); | 865 | dev_name(&dev->dev)); |
837 | 866 | ||
867 | dev->rfkill = rfkill_alloc(dev_name(&dev->dev), &dev->dev, | ||
868 | RFKILL_TYPE_NFC, &nfc_rfkill_ops, dev); | ||
869 | if (dev->rfkill) { | ||
870 | if (rfkill_register(dev->rfkill) < 0) { | ||
871 | rfkill_destroy(dev->rfkill); | ||
872 | dev->rfkill = NULL; | ||
873 | } | ||
874 | } | ||
875 | |||
838 | return 0; | 876 | return 0; |
839 | } | 877 | } |
840 | EXPORT_SYMBOL(nfc_register_device); | 878 | EXPORT_SYMBOL(nfc_register_device); |
@@ -852,6 +890,11 @@ void nfc_unregister_device(struct nfc_dev *dev) | |||
852 | 890 | ||
853 | id = dev->idx; | 891 | id = dev->idx; |
854 | 892 | ||
893 | if (dev->rfkill) { | ||
894 | rfkill_unregister(dev->rfkill); | ||
895 | rfkill_destroy(dev->rfkill); | ||
896 | } | ||
897 | |||
855 | if (dev->ops->check_presence) { | 898 | if (dev->ops->check_presence) { |
856 | device_lock(&dev->dev); | 899 | device_lock(&dev->dev); |
857 | dev->shutting_down = true; | 900 | dev->shutting_down = true; |
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index b75a9b3f9e89..094f7e27e910 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c | |||
@@ -420,7 +420,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock) | |||
420 | } | 420 | } |
421 | 421 | ||
422 | /* If the socket parameters are not set, use the local ones */ | 422 | /* If the socket parameters are not set, use the local ones */ |
423 | miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux; | 423 | miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ? |
424 | local->miux : sock->miux; | ||
424 | rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw; | 425 | rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw; |
425 | 426 | ||
426 | miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, | 427 | miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, |
@@ -475,7 +476,8 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock) | |||
475 | return -ENODEV; | 476 | return -ENODEV; |
476 | 477 | ||
477 | /* If the socket parameters are not set, use the local ones */ | 478 | /* If the socket parameters are not set, use the local ones */ |
478 | miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux; | 479 | miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ? |
480 | local->miux : sock->miux; | ||
479 | rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw; | 481 | rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw; |
480 | 482 | ||
481 | miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, | 483 | miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0, |
@@ -656,6 +658,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | |||
656 | struct nfc_llcp_local *local; | 658 | struct nfc_llcp_local *local; |
657 | size_t frag_len = 0, remaining_len; | 659 | size_t frag_len = 0, remaining_len; |
658 | u8 *msg_data, *msg_ptr; | 660 | u8 *msg_data, *msg_ptr; |
661 | u16 remote_miu; | ||
659 | 662 | ||
660 | pr_debug("Send I frame len %zd\n", len); | 663 | pr_debug("Send I frame len %zd\n", len); |
661 | 664 | ||
@@ -692,9 +695,11 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | |||
692 | remaining_len = len; | 695 | remaining_len = len; |
693 | msg_ptr = msg_data; | 696 | msg_ptr = msg_data; |
694 | 697 | ||
695 | while (remaining_len > 0) { | 698 | do { |
699 | remote_miu = sock->remote_miu > LLCP_MAX_MIU ? | ||
700 | local->remote_miu : sock->remote_miu; | ||
696 | 701 | ||
697 | frag_len = min_t(size_t, sock->remote_miu, remaining_len); | 702 | frag_len = min_t(size_t, remote_miu, remaining_len); |
698 | 703 | ||
699 | pr_debug("Fragment %zd bytes remaining %zd", | 704 | pr_debug("Fragment %zd bytes remaining %zd", |
700 | frag_len, remaining_len); | 705 | frag_len, remaining_len); |
@@ -706,7 +711,8 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | |||
706 | 711 | ||
707 | skb_put(pdu, LLCP_SEQUENCE_SIZE); | 712 | skb_put(pdu, LLCP_SEQUENCE_SIZE); |
708 | 713 | ||
709 | memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); | 714 | if (likely(frag_len > 0)) |
715 | memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); | ||
710 | 716 | ||
711 | skb_queue_tail(&sock->tx_queue, pdu); | 717 | skb_queue_tail(&sock->tx_queue, pdu); |
712 | 718 | ||
@@ -718,7 +724,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, | |||
718 | 724 | ||
719 | remaining_len -= frag_len; | 725 | remaining_len -= frag_len; |
720 | msg_ptr += frag_len; | 726 | msg_ptr += frag_len; |
721 | } | 727 | } while (remaining_len > 0); |
722 | 728 | ||
723 | kfree(msg_data); | 729 | kfree(msg_data); |
724 | 730 | ||
@@ -732,6 +738,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, | |||
732 | struct nfc_llcp_local *local; | 738 | struct nfc_llcp_local *local; |
733 | size_t frag_len = 0, remaining_len; | 739 | size_t frag_len = 0, remaining_len; |
734 | u8 *msg_ptr, *msg_data; | 740 | u8 *msg_ptr, *msg_data; |
741 | u16 remote_miu; | ||
735 | int err; | 742 | int err; |
736 | 743 | ||
737 | pr_debug("Send UI frame len %zd\n", len); | 744 | pr_debug("Send UI frame len %zd\n", len); |
@@ -752,9 +759,11 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, | |||
752 | remaining_len = len; | 759 | remaining_len = len; |
753 | msg_ptr = msg_data; | 760 | msg_ptr = msg_data; |
754 | 761 | ||
755 | while (remaining_len > 0) { | 762 | do { |
763 | remote_miu = sock->remote_miu > LLCP_MAX_MIU ? | ||
764 | local->remote_miu : sock->remote_miu; | ||
756 | 765 | ||
757 | frag_len = min_t(size_t, sock->remote_miu, remaining_len); | 766 | frag_len = min_t(size_t, remote_miu, remaining_len); |
758 | 767 | ||
759 | pr_debug("Fragment %zd bytes remaining %zd", | 768 | pr_debug("Fragment %zd bytes remaining %zd", |
760 | frag_len, remaining_len); | 769 | frag_len, remaining_len); |
@@ -768,14 +777,15 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap, | |||
768 | 777 | ||
769 | pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI); | 778 | pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI); |
770 | 779 | ||
771 | memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); | 780 | if (likely(frag_len > 0)) |
781 | memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); | ||
772 | 782 | ||
773 | /* No need to check for the peer RW for UI frames */ | 783 | /* No need to check for the peer RW for UI frames */ |
774 | skb_queue_tail(&local->tx_queue, pdu); | 784 | skb_queue_tail(&local->tx_queue, pdu); |
775 | 785 | ||
776 | remaining_len -= frag_len; | 786 | remaining_len -= frag_len; |
777 | msg_ptr += frag_len; | 787 | msg_ptr += frag_len; |
778 | } | 788 | } while (remaining_len > 0); |
779 | 789 | ||
780 | kfree(msg_data); | 790 | kfree(msg_data); |
781 | 791 | ||
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 7de0368aff0c..9e483c8e52f8 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c | |||
@@ -31,6 +31,8 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d}; | |||
31 | 31 | ||
32 | static struct list_head llcp_devices; | 32 | static struct list_head llcp_devices; |
33 | 33 | ||
34 | static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb); | ||
35 | |||
34 | void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk) | 36 | void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk) |
35 | { | 37 | { |
36 | write_lock(&l->lock); | 38 | write_lock(&l->lock); |
@@ -45,6 +47,12 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk) | |||
45 | write_unlock(&l->lock); | 47 | write_unlock(&l->lock); |
46 | } | 48 | } |
47 | 49 | ||
50 | void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock) | ||
51 | { | ||
52 | sock->remote_rw = LLCP_DEFAULT_RW; | ||
53 | sock->remote_miu = LLCP_MAX_MIU + 1; | ||
54 | } | ||
55 | |||
48 | static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock) | 56 | static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock) |
49 | { | 57 | { |
50 | struct nfc_llcp_local *local = sock->local; | 58 | struct nfc_llcp_local *local = sock->local; |
@@ -68,7 +76,7 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock) | |||
68 | } | 76 | } |
69 | } | 77 | } |
70 | 78 | ||
71 | static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, | 79 | static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool device, |
72 | int err) | 80 | int err) |
73 | { | 81 | { |
74 | struct sock *sk; | 82 | struct sock *sk; |
@@ -108,21 +116,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, | |||
108 | 116 | ||
109 | bh_unlock_sock(accept_sk); | 117 | bh_unlock_sock(accept_sk); |
110 | } | 118 | } |
111 | |||
112 | if (listen == true) { | ||
113 | bh_unlock_sock(sk); | ||
114 | continue; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * If we have a connection less socket bound, we keep it alive | ||
120 | * if the device is still present. | ||
121 | */ | ||
122 | if (sk->sk_state == LLCP_BOUND && sk->sk_type == SOCK_DGRAM && | ||
123 | listen == true) { | ||
124 | bh_unlock_sock(sk); | ||
125 | continue; | ||
126 | } | 119 | } |
127 | 120 | ||
128 | if (err) | 121 | if (err) |
@@ -137,11 +130,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen, | |||
137 | 130 | ||
138 | write_unlock(&local->sockets.lock); | 131 | write_unlock(&local->sockets.lock); |
139 | 132 | ||
140 | /* | 133 | /* If we still have a device, we keep the RAW sockets alive */ |
141 | * If we want to keep the listening sockets alive, | 134 | if (device == true) |
142 | * we don't touch the RAW ones. | ||
143 | */ | ||
144 | if (listen == true) | ||
145 | return; | 135 | return; |
146 | 136 | ||
147 | write_lock(&local->raw_sockets.lock); | 137 | write_lock(&local->raw_sockets.lock); |
@@ -173,9 +163,9 @@ struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) | |||
173 | return local; | 163 | return local; |
174 | } | 164 | } |
175 | 165 | ||
176 | static void local_cleanup(struct nfc_llcp_local *local, bool listen) | 166 | static void local_cleanup(struct nfc_llcp_local *local) |
177 | { | 167 | { |
178 | nfc_llcp_socket_release(local, listen, ENXIO); | 168 | nfc_llcp_socket_release(local, false, ENXIO); |
179 | del_timer_sync(&local->link_timer); | 169 | del_timer_sync(&local->link_timer); |
180 | skb_queue_purge(&local->tx_queue); | 170 | skb_queue_purge(&local->tx_queue); |
181 | cancel_work_sync(&local->tx_work); | 171 | cancel_work_sync(&local->tx_work); |
@@ -194,7 +184,7 @@ static void local_release(struct kref *ref) | |||
194 | local = container_of(ref, struct nfc_llcp_local, ref); | 184 | local = container_of(ref, struct nfc_llcp_local, ref); |
195 | 185 | ||
196 | list_del(&local->list); | 186 | list_del(&local->list); |
197 | local_cleanup(local, false); | 187 | local_cleanup(local); |
198 | kfree(local); | 188 | kfree(local); |
199 | } | 189 | } |
200 | 190 | ||
@@ -1116,6 +1106,12 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local, | |||
1116 | dsap = nfc_llcp_dsap(skb); | 1106 | dsap = nfc_llcp_dsap(skb); |
1117 | ssap = nfc_llcp_ssap(skb); | 1107 | ssap = nfc_llcp_ssap(skb); |
1118 | 1108 | ||
1109 | if ((dsap == 0) && (ssap == 0)) { | ||
1110 | pr_debug("Connection termination"); | ||
1111 | nfc_dep_link_down(local->dev); | ||
1112 | return; | ||
1113 | } | ||
1114 | |||
1119 | llcp_sock = nfc_llcp_sock_get(local, dsap, ssap); | 1115 | llcp_sock = nfc_llcp_sock_get(local, dsap, ssap); |
1120 | if (llcp_sock == NULL) { | 1116 | if (llcp_sock == NULL) { |
1121 | nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN); | 1117 | nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN); |
@@ -1349,19 +1345,54 @@ exit: | |||
1349 | nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len); | 1345 | nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len); |
1350 | } | 1346 | } |
1351 | 1347 | ||
1352 | static void nfc_llcp_rx_work(struct work_struct *work) | 1348 | static void nfc_llcp_recv_agf(struct nfc_llcp_local *local, struct sk_buff *skb) |
1353 | { | 1349 | { |
1354 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | 1350 | u8 ptype; |
1355 | rx_work); | 1351 | u16 pdu_len; |
1356 | u8 dsap, ssap, ptype; | 1352 | struct sk_buff *new_skb; |
1357 | struct sk_buff *skb; | ||
1358 | 1353 | ||
1359 | skb = local->rx_pending; | 1354 | if (skb->len <= LLCP_HEADER_SIZE) { |
1360 | if (skb == NULL) { | 1355 | pr_err("Malformed AGF PDU\n"); |
1361 | pr_debug("No pending SKB\n"); | ||
1362 | return; | 1356 | return; |
1363 | } | 1357 | } |
1364 | 1358 | ||
1359 | skb_pull(skb, LLCP_HEADER_SIZE); | ||
1360 | |||
1361 | while (skb->len > LLCP_AGF_PDU_HEADER_SIZE) { | ||
1362 | pdu_len = skb->data[0] << 8 | skb->data[1]; | ||
1363 | |||
1364 | skb_pull(skb, LLCP_AGF_PDU_HEADER_SIZE); | ||
1365 | |||
1366 | if (pdu_len < LLCP_HEADER_SIZE || pdu_len > skb->len) { | ||
1367 | pr_err("Malformed AGF PDU\n"); | ||
1368 | return; | ||
1369 | } | ||
1370 | |||
1371 | ptype = nfc_llcp_ptype(skb); | ||
1372 | |||
1373 | if (ptype == LLCP_PDU_SYMM || ptype == LLCP_PDU_AGF) | ||
1374 | goto next; | ||
1375 | |||
1376 | new_skb = nfc_alloc_recv_skb(pdu_len, GFP_KERNEL); | ||
1377 | if (new_skb == NULL) { | ||
1378 | pr_err("Could not allocate PDU\n"); | ||
1379 | return; | ||
1380 | } | ||
1381 | |||
1382 | memcpy(skb_put(new_skb, pdu_len), skb->data, pdu_len); | ||
1383 | |||
1384 | nfc_llcp_rx_skb(local, new_skb); | ||
1385 | |||
1386 | kfree_skb(new_skb); | ||
1387 | next: | ||
1388 | skb_pull(skb, pdu_len); | ||
1389 | } | ||
1390 | } | ||
1391 | |||
1392 | static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb) | ||
1393 | { | ||
1394 | u8 dsap, ssap, ptype; | ||
1395 | |||
1365 | ptype = nfc_llcp_ptype(skb); | 1396 | ptype = nfc_llcp_ptype(skb); |
1366 | dsap = nfc_llcp_dsap(skb); | 1397 | dsap = nfc_llcp_dsap(skb); |
1367 | ssap = nfc_llcp_ssap(skb); | 1398 | ssap = nfc_llcp_ssap(skb); |
@@ -1372,10 +1403,6 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
1372 | print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, | 1403 | print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET, |
1373 | 16, 1, skb->data, skb->len, true); | 1404 | 16, 1, skb->data, skb->len, true); |
1374 | 1405 | ||
1375 | __net_timestamp(skb); | ||
1376 | |||
1377 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX); | ||
1378 | |||
1379 | switch (ptype) { | 1406 | switch (ptype) { |
1380 | case LLCP_PDU_SYMM: | 1407 | case LLCP_PDU_SYMM: |
1381 | pr_debug("SYMM\n"); | 1408 | pr_debug("SYMM\n"); |
@@ -1418,7 +1445,30 @@ static void nfc_llcp_rx_work(struct work_struct *work) | |||
1418 | nfc_llcp_recv_hdlc(local, skb); | 1445 | nfc_llcp_recv_hdlc(local, skb); |
1419 | break; | 1446 | break; |
1420 | 1447 | ||
1448 | case LLCP_PDU_AGF: | ||
1449 | pr_debug("AGF frame\n"); | ||
1450 | nfc_llcp_recv_agf(local, skb); | ||
1451 | break; | ||
1421 | } | 1452 | } |
1453 | } | ||
1454 | |||
1455 | static void nfc_llcp_rx_work(struct work_struct *work) | ||
1456 | { | ||
1457 | struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, | ||
1458 | rx_work); | ||
1459 | struct sk_buff *skb; | ||
1460 | |||
1461 | skb = local->rx_pending; | ||
1462 | if (skb == NULL) { | ||
1463 | pr_debug("No pending SKB\n"); | ||
1464 | return; | ||
1465 | } | ||
1466 | |||
1467 | __net_timestamp(skb); | ||
1468 | |||
1469 | nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX); | ||
1470 | |||
1471 | nfc_llcp_rx_skb(local, skb); | ||
1422 | 1472 | ||
1423 | schedule_work(&local->tx_work); | 1473 | schedule_work(&local->tx_work); |
1424 | kfree_skb(local->rx_pending); | 1474 | kfree_skb(local->rx_pending); |
@@ -1466,6 +1516,9 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) | |||
1466 | if (local == NULL) | 1516 | if (local == NULL) |
1467 | return; | 1517 | return; |
1468 | 1518 | ||
1519 | local->remote_miu = LLCP_DEFAULT_MIU; | ||
1520 | local->remote_lto = LLCP_DEFAULT_LTO; | ||
1521 | |||
1469 | /* Close and purge all existing sockets */ | 1522 | /* Close and purge all existing sockets */ |
1470 | nfc_llcp_socket_release(local, true, 0); | 1523 | nfc_llcp_socket_release(local, true, 0); |
1471 | } | 1524 | } |
@@ -1553,7 +1606,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev) | |||
1553 | return; | 1606 | return; |
1554 | } | 1607 | } |
1555 | 1608 | ||
1556 | local_cleanup(local, false); | 1609 | local_cleanup(local); |
1557 | 1610 | ||
1558 | nfc_llcp_local_put(local); | 1611 | nfc_llcp_local_put(local); |
1559 | } | 1612 | } |
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 7e87a66b02ec..ff8c434f7df8 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h | |||
@@ -31,6 +31,7 @@ enum llcp_state { | |||
31 | #define LLCP_MAX_LTO 0xff | 31 | #define LLCP_MAX_LTO 0xff |
32 | #define LLCP_MAX_RW 15 | 32 | #define LLCP_MAX_RW 15 |
33 | #define LLCP_MAX_MIUX 0x7ff | 33 | #define LLCP_MAX_MIUX 0x7ff |
34 | #define LLCP_MAX_MIU (LLCP_MAX_MIUX + 128) | ||
34 | 35 | ||
35 | #define LLCP_WKS_NUM_SAP 16 | 36 | #define LLCP_WKS_NUM_SAP 16 |
36 | #define LLCP_SDP_NUM_SAP 16 | 37 | #define LLCP_SDP_NUM_SAP 16 |
@@ -124,7 +125,7 @@ struct nfc_llcp_sock { | |||
124 | char *service_name; | 125 | char *service_name; |
125 | size_t service_name_len; | 126 | size_t service_name_len; |
126 | u8 rw; | 127 | u8 rw; |
127 | u16 miux; | 128 | __be16 miux; |
128 | 129 | ||
129 | 130 | ||
130 | /* Remote link parameters */ | 131 | /* Remote link parameters */ |
@@ -162,6 +163,7 @@ struct nfc_llcp_ui_cb { | |||
162 | 163 | ||
163 | #define LLCP_HEADER_SIZE 2 | 164 | #define LLCP_HEADER_SIZE 2 |
164 | #define LLCP_SEQUENCE_SIZE 1 | 165 | #define LLCP_SEQUENCE_SIZE 1 |
166 | #define LLCP_AGF_PDU_HEADER_SIZE 2 | ||
165 | 167 | ||
166 | /* LLCP versions: 1.1 is 1.0 plus SDP */ | 168 | /* LLCP versions: 1.1 is 1.0 plus SDP */ |
167 | #define LLCP_VERSION_10 0x10 | 169 | #define LLCP_VERSION_10 0x10 |
@@ -210,6 +212,7 @@ struct nfc_llcp_ui_cb { | |||
210 | 212 | ||
211 | void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s); | 213 | void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s); |
212 | void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s); | 214 | void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s); |
215 | void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock); | ||
213 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev); | 216 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev); |
214 | struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local); | 217 | struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local); |
215 | int nfc_llcp_local_put(struct nfc_llcp_local *local); | 218 | int nfc_llcp_local_put(struct nfc_llcp_local *local); |
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index c1101e6de170..d6faa47c9bba 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c | |||
@@ -279,7 +279,7 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname, | |||
279 | break; | 279 | break; |
280 | } | 280 | } |
281 | 281 | ||
282 | llcp_sock->miux = (u16) opt; | 282 | llcp_sock->miux = cpu_to_be16((u16) opt); |
283 | 283 | ||
284 | break; | 284 | break; |
285 | 285 | ||
@@ -299,9 +299,12 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname, | |||
299 | static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname, | 299 | static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname, |
300 | char __user *optval, int __user *optlen) | 300 | char __user *optval, int __user *optlen) |
301 | { | 301 | { |
302 | struct nfc_llcp_local *local; | ||
302 | struct sock *sk = sock->sk; | 303 | struct sock *sk = sock->sk; |
303 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | 304 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); |
304 | int len, err = 0; | 305 | int len, err = 0; |
306 | u16 miux, remote_miu; | ||
307 | u8 rw; | ||
305 | 308 | ||
306 | pr_debug("%p optname %d\n", sk, optname); | 309 | pr_debug("%p optname %d\n", sk, optname); |
307 | 310 | ||
@@ -311,19 +314,48 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname, | |||
311 | if (get_user(len, optlen)) | 314 | if (get_user(len, optlen)) |
312 | return -EFAULT; | 315 | return -EFAULT; |
313 | 316 | ||
317 | local = llcp_sock->local; | ||
318 | if (!local) | ||
319 | return -ENODEV; | ||
320 | |||
314 | len = min_t(u32, len, sizeof(u32)); | 321 | len = min_t(u32, len, sizeof(u32)); |
315 | 322 | ||
316 | lock_sock(sk); | 323 | lock_sock(sk); |
317 | 324 | ||
318 | switch (optname) { | 325 | switch (optname) { |
319 | case NFC_LLCP_RW: | 326 | case NFC_LLCP_RW: |
320 | if (put_user(llcp_sock->rw, (u32 __user *) optval)) | 327 | rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw; |
328 | if (put_user(rw, (u32 __user *) optval)) | ||
321 | err = -EFAULT; | 329 | err = -EFAULT; |
322 | 330 | ||
323 | break; | 331 | break; |
324 | 332 | ||
325 | case NFC_LLCP_MIUX: | 333 | case NFC_LLCP_MIUX: |
326 | if (put_user(llcp_sock->miux, (u32 __user *) optval)) | 334 | miux = be16_to_cpu(llcp_sock->miux) > LLCP_MAX_MIUX ? |
335 | be16_to_cpu(local->miux) : be16_to_cpu(llcp_sock->miux); | ||
336 | |||
337 | if (put_user(miux, (u32 __user *) optval)) | ||
338 | err = -EFAULT; | ||
339 | |||
340 | break; | ||
341 | |||
342 | case NFC_LLCP_REMOTE_MIU: | ||
343 | remote_miu = llcp_sock->remote_miu > LLCP_MAX_MIU ? | ||
344 | local->remote_miu : llcp_sock->remote_miu; | ||
345 | |||
346 | if (put_user(remote_miu, (u32 __user *) optval)) | ||
347 | err = -EFAULT; | ||
348 | |||
349 | break; | ||
350 | |||
351 | case NFC_LLCP_REMOTE_LTO: | ||
352 | if (put_user(local->remote_lto / 10, (u32 __user *) optval)) | ||
353 | err = -EFAULT; | ||
354 | |||
355 | break; | ||
356 | |||
357 | case NFC_LLCP_REMOTE_RW: | ||
358 | if (put_user(llcp_sock->remote_rw, (u32 __user *) optval)) | ||
327 | err = -EFAULT; | 359 | err = -EFAULT; |
328 | 360 | ||
329 | break; | 361 | break; |
@@ -925,13 +957,12 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp) | |||
925 | llcp_sock->ssap = 0; | 957 | llcp_sock->ssap = 0; |
926 | llcp_sock->dsap = LLCP_SAP_SDP; | 958 | llcp_sock->dsap = LLCP_SAP_SDP; |
927 | llcp_sock->rw = LLCP_MAX_RW + 1; | 959 | llcp_sock->rw = LLCP_MAX_RW + 1; |
928 | llcp_sock->miux = LLCP_MAX_MIUX + 1; | 960 | llcp_sock->miux = cpu_to_be16(LLCP_MAX_MIUX + 1); |
929 | llcp_sock->remote_rw = LLCP_DEFAULT_RW; | ||
930 | llcp_sock->remote_miu = LLCP_DEFAULT_MIU; | ||
931 | llcp_sock->send_n = llcp_sock->send_ack_n = 0; | 961 | llcp_sock->send_n = llcp_sock->send_ack_n = 0; |
932 | llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; | 962 | llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; |
933 | llcp_sock->remote_ready = 1; | 963 | llcp_sock->remote_ready = 1; |
934 | llcp_sock->reserved_ssap = LLCP_SAP_MAX; | 964 | llcp_sock->reserved_ssap = LLCP_SAP_MAX; |
965 | nfc_llcp_socket_remote_param_init(llcp_sock); | ||
935 | skb_queue_head_init(&llcp_sock->tx_queue); | 966 | skb_queue_head_init(&llcp_sock->tx_queue); |
936 | skb_queue_head_init(&llcp_sock->tx_pending_queue); | 967 | skb_queue_head_init(&llcp_sock->tx_pending_queue); |
937 | INIT_LIST_HEAD(&llcp_sock->accept_queue); | 968 | INIT_LIST_HEAD(&llcp_sock->accept_queue); |