.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2011 Intel Corporation. All rights reserved. |
---|
3 | 4 | * Copyright (C) 2014 Marvell International Ltd. |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify |
---|
6 | | - * it under the terms of the GNU General Public License as published by |
---|
7 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
8 | | - * (at your option) any later version. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, |
---|
11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | | - * GNU General Public License for more details. |
---|
14 | | - * |
---|
15 | | - * You should have received a copy of the GNU General Public License |
---|
16 | | - * along with this program; if not, see <http://www.gnu.org/licenses/>. |
---|
17 | 5 | */ |
---|
18 | 6 | |
---|
19 | 7 | #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ |
---|
.. | .. |
---|
29 | 17 | static u8 llcp_magic[3] = {0x46, 0x66, 0x6d}; |
---|
30 | 18 | |
---|
31 | 19 | static LIST_HEAD(llcp_devices); |
---|
| 20 | +/* Protects llcp_devices list */ |
---|
| 21 | +static DEFINE_SPINLOCK(llcp_devices_lock); |
---|
32 | 22 | |
---|
33 | 23 | static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb); |
---|
34 | 24 | |
---|
.. | .. |
---|
155 | 145 | write_unlock(&local->raw_sockets.lock); |
---|
156 | 146 | } |
---|
157 | 147 | |
---|
158 | | -struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) |
---|
| 148 | +static struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local) |
---|
159 | 149 | { |
---|
160 | 150 | kref_get(&local->ref); |
---|
161 | 151 | |
---|
.. | .. |
---|
171 | 161 | cancel_work_sync(&local->rx_work); |
---|
172 | 162 | cancel_work_sync(&local->timeout_work); |
---|
173 | 163 | kfree_skb(local->rx_pending); |
---|
| 164 | + local->rx_pending = NULL; |
---|
174 | 165 | del_timer_sync(&local->sdreq_timer); |
---|
175 | 166 | cancel_work_sync(&local->sdreq_timeout_work); |
---|
176 | 167 | nfc_llcp_free_sdp_tlv_list(&local->pending_sdreqs); |
---|
.. | .. |
---|
182 | 173 | |
---|
183 | 174 | local = container_of(ref, struct nfc_llcp_local, ref); |
---|
184 | 175 | |
---|
185 | | - list_del(&local->list); |
---|
186 | 176 | local_cleanup(local); |
---|
187 | 177 | kfree(local); |
---|
188 | 178 | } |
---|
.. | .. |
---|
295 | 285 | struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) |
---|
296 | 286 | { |
---|
297 | 287 | struct nfc_llcp_local *local; |
---|
| 288 | + struct nfc_llcp_local *res = NULL; |
---|
298 | 289 | |
---|
| 290 | + spin_lock(&llcp_devices_lock); |
---|
299 | 291 | list_for_each_entry(local, &llcp_devices, list) |
---|
300 | | - if (local->dev == dev) |
---|
301 | | - return local; |
---|
| 292 | + if (local->dev == dev) { |
---|
| 293 | + res = nfc_llcp_local_get(local); |
---|
| 294 | + break; |
---|
| 295 | + } |
---|
| 296 | + spin_unlock(&llcp_devices_lock); |
---|
302 | 297 | |
---|
303 | | - pr_debug("No device found\n"); |
---|
| 298 | + return res; |
---|
| 299 | +} |
---|
| 300 | + |
---|
| 301 | +static struct nfc_llcp_local *nfc_llcp_remove_local(struct nfc_dev *dev) |
---|
| 302 | +{ |
---|
| 303 | + struct nfc_llcp_local *local, *tmp; |
---|
| 304 | + |
---|
| 305 | + spin_lock(&llcp_devices_lock); |
---|
| 306 | + list_for_each_entry_safe(local, tmp, &llcp_devices, list) |
---|
| 307 | + if (local->dev == dev) { |
---|
| 308 | + list_del(&local->list); |
---|
| 309 | + spin_unlock(&llcp_devices_lock); |
---|
| 310 | + return local; |
---|
| 311 | + } |
---|
| 312 | + spin_unlock(&llcp_devices_lock); |
---|
| 313 | + |
---|
| 314 | + pr_warn("Shutting down device not found\n"); |
---|
304 | 315 | |
---|
305 | 316 | return NULL; |
---|
306 | 317 | } |
---|
.. | .. |
---|
313 | 324 | "urn:nfc:sn:snep", |
---|
314 | 325 | }; |
---|
315 | 326 | |
---|
316 | | -static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len) |
---|
| 327 | +static int nfc_llcp_wks_sap(const char *service_name, size_t service_name_len) |
---|
317 | 328 | { |
---|
318 | 329 | int sap, num_wks; |
---|
319 | 330 | |
---|
.. | .. |
---|
337 | 348 | |
---|
338 | 349 | static |
---|
339 | 350 | struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local, |
---|
340 | | - u8 *sn, size_t sn_len) |
---|
| 351 | + const u8 *sn, size_t sn_len) |
---|
341 | 352 | { |
---|
342 | 353 | struct sock *sk; |
---|
343 | 354 | struct nfc_llcp_sock *llcp_sock, *tmp_sock; |
---|
.. | .. |
---|
534 | 545 | { |
---|
535 | 546 | u8 *gb_cur, version, version_length; |
---|
536 | 547 | u8 lto_length, wks_length, miux_length; |
---|
537 | | - u8 *version_tlv = NULL, *lto_tlv = NULL, |
---|
| 548 | + const u8 *version_tlv = NULL, *lto_tlv = NULL, |
---|
538 | 549 | *wks_tlv = NULL, *miux_tlv = NULL; |
---|
539 | 550 | __be16 wks = cpu_to_be16(local->local_wks); |
---|
540 | 551 | u8 gb_len = 0; |
---|
.. | .. |
---|
621 | 632 | |
---|
622 | 633 | *general_bytes_len = local->gb_len; |
---|
623 | 634 | |
---|
| 635 | + nfc_llcp_local_put(local); |
---|
| 636 | + |
---|
624 | 637 | return local->gb; |
---|
625 | 638 | } |
---|
626 | 639 | |
---|
627 | | -int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) |
---|
| 640 | +int nfc_llcp_set_remote_gb(struct nfc_dev *dev, const u8 *gb, u8 gb_len) |
---|
628 | 641 | { |
---|
629 | 642 | struct nfc_llcp_local *local; |
---|
| 643 | + int err; |
---|
630 | 644 | |
---|
631 | 645 | if (gb_len < 3 || gb_len > NFC_MAX_GT_LEN) |
---|
632 | 646 | return -EINVAL; |
---|
.. | .. |
---|
643 | 657 | |
---|
644 | 658 | if (memcmp(local->remote_gb, llcp_magic, 3)) { |
---|
645 | 659 | pr_err("MAC does not support LLCP\n"); |
---|
646 | | - return -EINVAL; |
---|
| 660 | + err = -EINVAL; |
---|
| 661 | + goto out; |
---|
647 | 662 | } |
---|
648 | 663 | |
---|
649 | | - return nfc_llcp_parse_gb_tlv(local, |
---|
| 664 | + err = nfc_llcp_parse_gb_tlv(local, |
---|
650 | 665 | &local->remote_gb[3], |
---|
651 | 666 | local->remote_gb_len - 3); |
---|
| 667 | +out: |
---|
| 668 | + nfc_llcp_local_put(local); |
---|
| 669 | + return err; |
---|
652 | 670 | } |
---|
653 | 671 | |
---|
654 | | -static u8 nfc_llcp_dsap(struct sk_buff *pdu) |
---|
| 672 | +static u8 nfc_llcp_dsap(const struct sk_buff *pdu) |
---|
655 | 673 | { |
---|
656 | 674 | return (pdu->data[0] & 0xfc) >> 2; |
---|
657 | 675 | } |
---|
658 | 676 | |
---|
659 | | -static u8 nfc_llcp_ptype(struct sk_buff *pdu) |
---|
| 677 | +static u8 nfc_llcp_ptype(const struct sk_buff *pdu) |
---|
660 | 678 | { |
---|
661 | 679 | return ((pdu->data[0] & 0x03) << 2) | ((pdu->data[1] & 0xc0) >> 6); |
---|
662 | 680 | } |
---|
663 | 681 | |
---|
664 | | -static u8 nfc_llcp_ssap(struct sk_buff *pdu) |
---|
| 682 | +static u8 nfc_llcp_ssap(const struct sk_buff *pdu) |
---|
665 | 683 | { |
---|
666 | 684 | return pdu->data[1] & 0x3f; |
---|
667 | 685 | } |
---|
668 | 686 | |
---|
669 | | -static u8 nfc_llcp_ns(struct sk_buff *pdu) |
---|
| 687 | +static u8 nfc_llcp_ns(const struct sk_buff *pdu) |
---|
670 | 688 | { |
---|
671 | 689 | return pdu->data[2] >> 4; |
---|
672 | 690 | } |
---|
673 | 691 | |
---|
674 | | -static u8 nfc_llcp_nr(struct sk_buff *pdu) |
---|
| 692 | +static u8 nfc_llcp_nr(const struct sk_buff *pdu) |
---|
675 | 693 | { |
---|
676 | 694 | return pdu->data[2] & 0xf; |
---|
677 | 695 | } |
---|
.. | .. |
---|
813 | 831 | } |
---|
814 | 832 | |
---|
815 | 833 | static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, |
---|
816 | | - u8 *sn, size_t sn_len) |
---|
| 834 | + const u8 *sn, size_t sn_len) |
---|
817 | 835 | { |
---|
818 | 836 | struct nfc_llcp_sock *llcp_sock; |
---|
819 | 837 | |
---|
.. | .. |
---|
827 | 845 | return llcp_sock; |
---|
828 | 846 | } |
---|
829 | 847 | |
---|
830 | | -static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len) |
---|
| 848 | +static const u8 *nfc_llcp_connect_sn(const struct sk_buff *skb, size_t *sn_len) |
---|
831 | 849 | { |
---|
832 | | - u8 *tlv = &skb->data[2], type, length; |
---|
| 850 | + u8 type, length; |
---|
| 851 | + const u8 *tlv = &skb->data[2]; |
---|
833 | 852 | size_t tlv_array_len = skb->len - LLCP_HEADER_SIZE, offset = 0; |
---|
834 | 853 | |
---|
835 | 854 | while (offset < tlv_array_len) { |
---|
.. | .. |
---|
887 | 906 | } |
---|
888 | 907 | |
---|
889 | 908 | static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, |
---|
890 | | - struct sk_buff *skb) |
---|
| 909 | + const struct sk_buff *skb) |
---|
891 | 910 | { |
---|
892 | 911 | struct sock *new_sk, *parent; |
---|
893 | 912 | struct nfc_llcp_sock *sock, *new_sock; |
---|
.. | .. |
---|
905 | 924 | goto fail; |
---|
906 | 925 | } |
---|
907 | 926 | } else { |
---|
908 | | - u8 *sn; |
---|
| 927 | + const u8 *sn; |
---|
909 | 928 | size_t sn_len; |
---|
910 | 929 | |
---|
911 | 930 | sn = nfc_llcp_connect_sn(skb, &sn_len); |
---|
.. | .. |
---|
1124 | 1143 | } |
---|
1125 | 1144 | |
---|
1126 | 1145 | static void nfc_llcp_recv_disc(struct nfc_llcp_local *local, |
---|
1127 | | - struct sk_buff *skb) |
---|
| 1146 | + const struct sk_buff *skb) |
---|
1128 | 1147 | { |
---|
1129 | 1148 | struct nfc_llcp_sock *llcp_sock; |
---|
1130 | 1149 | struct sock *sk; |
---|
.. | .. |
---|
1167 | 1186 | nfc_llcp_sock_put(llcp_sock); |
---|
1168 | 1187 | } |
---|
1169 | 1188 | |
---|
1170 | | -static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) |
---|
| 1189 | +static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, |
---|
| 1190 | + const struct sk_buff *skb) |
---|
1171 | 1191 | { |
---|
1172 | 1192 | struct nfc_llcp_sock *llcp_sock; |
---|
1173 | 1193 | struct sock *sk; |
---|
.. | .. |
---|
1200 | 1220 | nfc_llcp_sock_put(llcp_sock); |
---|
1201 | 1221 | } |
---|
1202 | 1222 | |
---|
1203 | | -static void nfc_llcp_recv_dm(struct nfc_llcp_local *local, struct sk_buff *skb) |
---|
| 1223 | +static void nfc_llcp_recv_dm(struct nfc_llcp_local *local, |
---|
| 1224 | + const struct sk_buff *skb) |
---|
1204 | 1225 | { |
---|
1205 | 1226 | struct nfc_llcp_sock *llcp_sock; |
---|
1206 | 1227 | struct sock *sk; |
---|
.. | .. |
---|
1238 | 1259 | } |
---|
1239 | 1260 | |
---|
1240 | 1261 | static void nfc_llcp_recv_snl(struct nfc_llcp_local *local, |
---|
1241 | | - struct sk_buff *skb) |
---|
| 1262 | + const struct sk_buff *skb) |
---|
1242 | 1263 | { |
---|
1243 | 1264 | struct nfc_llcp_sock *llcp_sock; |
---|
1244 | | - u8 dsap, ssap, *tlv, type, length, tid, sap; |
---|
| 1265 | + u8 dsap, ssap, type, length, tid, sap; |
---|
| 1266 | + const u8 *tlv; |
---|
1245 | 1267 | u16 tlv_len, offset; |
---|
1246 | | - char *service_name; |
---|
| 1268 | + const char *service_name; |
---|
1247 | 1269 | size_t service_name_len; |
---|
1248 | 1270 | struct nfc_llcp_sdp_tlv *sdp; |
---|
1249 | 1271 | HLIST_HEAD(llc_sdres_list); |
---|
.. | .. |
---|
1534 | 1556 | |
---|
1535 | 1557 | __nfc_llcp_recv(local, skb); |
---|
1536 | 1558 | |
---|
| 1559 | + nfc_llcp_local_put(local); |
---|
| 1560 | + |
---|
1537 | 1561 | return 0; |
---|
1538 | 1562 | } |
---|
1539 | 1563 | |
---|
.. | .. |
---|
1550 | 1574 | |
---|
1551 | 1575 | /* Close and purge all existing sockets */ |
---|
1552 | 1576 | nfc_llcp_socket_release(local, true, 0); |
---|
| 1577 | + |
---|
| 1578 | + nfc_llcp_local_put(local); |
---|
1553 | 1579 | } |
---|
1554 | 1580 | |
---|
1555 | 1581 | void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, |
---|
.. | .. |
---|
1575 | 1601 | mod_timer(&local->link_timer, |
---|
1576 | 1602 | jiffies + msecs_to_jiffies(local->remote_lto)); |
---|
1577 | 1603 | } |
---|
| 1604 | + |
---|
| 1605 | + nfc_llcp_local_put(local); |
---|
1578 | 1606 | } |
---|
1579 | 1607 | |
---|
1580 | 1608 | int nfc_llcp_register_device(struct nfc_dev *ndev) |
---|
.. | .. |
---|
1618 | 1646 | timer_setup(&local->sdreq_timer, nfc_llcp_sdreq_timer, 0); |
---|
1619 | 1647 | INIT_WORK(&local->sdreq_timeout_work, nfc_llcp_sdreq_timeout_work); |
---|
1620 | 1648 | |
---|
| 1649 | + spin_lock(&llcp_devices_lock); |
---|
1621 | 1650 | list_add(&local->list, &llcp_devices); |
---|
| 1651 | + spin_unlock(&llcp_devices_lock); |
---|
1622 | 1652 | |
---|
1623 | 1653 | return 0; |
---|
1624 | 1654 | } |
---|
1625 | 1655 | |
---|
1626 | 1656 | void nfc_llcp_unregister_device(struct nfc_dev *dev) |
---|
1627 | 1657 | { |
---|
1628 | | - struct nfc_llcp_local *local = nfc_llcp_find_local(dev); |
---|
| 1658 | + struct nfc_llcp_local *local = nfc_llcp_remove_local(dev); |
---|
1629 | 1659 | |
---|
1630 | 1660 | if (local == NULL) { |
---|
1631 | 1661 | pr_debug("No such device\n"); |
---|