18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci BlueZ - Bluetooth protocol stack for Linux 38c2ecf20Sopenharmony_ci Copyright (C) 2000-2001 Qualcomm Incorporated 48c2ecf20Sopenharmony_ci Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org> 58c2ecf20Sopenharmony_ci Copyright (C) 2010 Google Inc. 68c2ecf20Sopenharmony_ci Copyright (C) 2011 ProFUSION Embedded Systems 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci This program is free software; you can redistribute it and/or modify 118c2ecf20Sopenharmony_ci it under the terms of the GNU General Public License version 2 as 128c2ecf20Sopenharmony_ci published by the Free Software Foundation; 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 158c2ecf20Sopenharmony_ci OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 168c2ecf20Sopenharmony_ci FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 178c2ecf20Sopenharmony_ci IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 188c2ecf20Sopenharmony_ci CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 198c2ecf20Sopenharmony_ci WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 208c2ecf20Sopenharmony_ci ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 218c2ecf20Sopenharmony_ci OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 248c2ecf20Sopenharmony_ci COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 258c2ecf20Sopenharmony_ci SOFTWARE IS DISCLAIMED. 268c2ecf20Sopenharmony_ci*/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Bluetooth L2CAP sockets. */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <linux/module.h> 318c2ecf20Sopenharmony_ci#include <linux/export.h> 328c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h> 358c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h> 368c2ecf20Sopenharmony_ci#include <net/bluetooth/l2cap.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "smp.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic struct bt_sock_list l2cap_sk_list = { 418c2ecf20Sopenharmony_ci .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic const struct proto_ops l2cap_sock_ops; 458c2ecf20Sopenharmony_cistatic void l2cap_sock_init(struct sock *sk, struct sock *parent); 468c2ecf20Sopenharmony_cistatic struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, 478c2ecf20Sopenharmony_ci int proto, gfp_t prio, int kern); 488c2ecf20Sopenharmony_cistatic void l2cap_sock_cleanup_listen(struct sock *parent); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cibool l2cap_is_socket(struct socket *sock) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return sock && sock->ops == &l2cap_sock_ops; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(l2cap_is_socket); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic int l2cap_validate_bredr_psm(u16 psm) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci /* PSM must be odd and lsb of upper byte must be 0 */ 598c2ecf20Sopenharmony_ci if ((psm & 0x0101) != 0x0001) 608c2ecf20Sopenharmony_ci return -EINVAL; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* Restrict usage of well-known PSMs */ 638c2ecf20Sopenharmony_ci if (psm < L2CAP_PSM_DYN_START && !capable(CAP_NET_BIND_SERVICE)) 648c2ecf20Sopenharmony_ci return -EACCES; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci return 0; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int l2cap_validate_le_psm(u16 psm) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci /* Valid LE_PSM ranges are defined only until 0x00ff */ 728c2ecf20Sopenharmony_ci if (psm > L2CAP_PSM_LE_DYN_END) 738c2ecf20Sopenharmony_ci return -EINVAL; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Restrict fixed, SIG assigned PSM values to CAP_NET_BIND_SERVICE */ 768c2ecf20Sopenharmony_ci if (psm < L2CAP_PSM_LE_DYN_START && !capable(CAP_NET_BIND_SERVICE)) 778c2ecf20Sopenharmony_ci return -EACCES; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 858c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 868c2ecf20Sopenharmony_ci struct sockaddr_l2 la; 878c2ecf20Sopenharmony_ci int len, err = 0; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci BT_DBG("sk %p", sk); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci if (!addr || alen < offsetofend(struct sockaddr, sa_family) || 928c2ecf20Sopenharmony_ci addr->sa_family != AF_BLUETOOTH) 938c2ecf20Sopenharmony_ci return -EINVAL; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci memset(&la, 0, sizeof(la)); 968c2ecf20Sopenharmony_ci len = min_t(unsigned int, sizeof(la), alen); 978c2ecf20Sopenharmony_ci memcpy(&la, addr, len); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (la.l2_cid && la.l2_psm) 1008c2ecf20Sopenharmony_ci return -EINVAL; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (!bdaddr_type_is_valid(la.l2_bdaddr_type)) 1038c2ecf20Sopenharmony_ci return -EINVAL; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (bdaddr_type_is_le(la.l2_bdaddr_type)) { 1068c2ecf20Sopenharmony_ci /* We only allow ATT user space socket */ 1078c2ecf20Sopenharmony_ci if (la.l2_cid && 1088c2ecf20Sopenharmony_ci la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) 1098c2ecf20Sopenharmony_ci return -EINVAL; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci lock_sock(sk); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (sk->sk_state != BT_OPEN) { 1158c2ecf20Sopenharmony_ci err = -EBADFD; 1168c2ecf20Sopenharmony_ci goto done; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (la.l2_psm) { 1208c2ecf20Sopenharmony_ci __u16 psm = __le16_to_cpu(la.l2_psm); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (la.l2_bdaddr_type == BDADDR_BREDR) 1238c2ecf20Sopenharmony_ci err = l2cap_validate_bredr_psm(psm); 1248c2ecf20Sopenharmony_ci else 1258c2ecf20Sopenharmony_ci err = l2cap_validate_le_psm(psm); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (err) 1288c2ecf20Sopenharmony_ci goto done; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci bacpy(&chan->src, &la.l2_bdaddr); 1328c2ecf20Sopenharmony_ci chan->src_type = la.l2_bdaddr_type; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (la.l2_cid) 1358c2ecf20Sopenharmony_ci err = l2cap_add_scid(chan, __le16_to_cpu(la.l2_cid)); 1368c2ecf20Sopenharmony_ci else 1378c2ecf20Sopenharmony_ci err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (err < 0) 1408c2ecf20Sopenharmony_ci goto done; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci switch (chan->chan_type) { 1438c2ecf20Sopenharmony_ci case L2CAP_CHAN_CONN_LESS: 1448c2ecf20Sopenharmony_ci if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_3DSP) 1458c2ecf20Sopenharmony_ci chan->sec_level = BT_SECURITY_SDP; 1468c2ecf20Sopenharmony_ci break; 1478c2ecf20Sopenharmony_ci case L2CAP_CHAN_CONN_ORIENTED: 1488c2ecf20Sopenharmony_ci if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP || 1498c2ecf20Sopenharmony_ci __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM) 1508c2ecf20Sopenharmony_ci chan->sec_level = BT_SECURITY_SDP; 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci case L2CAP_CHAN_RAW: 1538c2ecf20Sopenharmony_ci chan->sec_level = BT_SECURITY_SDP; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci case L2CAP_CHAN_FIXED: 1568c2ecf20Sopenharmony_ci /* Fixed channels default to the L2CAP core not holding a 1578c2ecf20Sopenharmony_ci * hci_conn reference for them. For fixed channels mapping to 1588c2ecf20Sopenharmony_ci * L2CAP sockets we do want to hold a reference so set the 1598c2ecf20Sopenharmony_ci * appropriate flag to request it. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci set_bit(FLAG_HOLD_HCI_CONN, &chan->flags); 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Use L2CAP_MODE_LE_FLOWCTL (CoC) in case of LE address and 1668c2ecf20Sopenharmony_ci * L2CAP_MODE_EXT_FLOWCTL (ECRED) has not been set. 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_ci if (chan->psm && bdaddr_type_is_le(chan->src_type) && 1698c2ecf20Sopenharmony_ci chan->mode != L2CAP_MODE_EXT_FLOWCTL) 1708c2ecf20Sopenharmony_ci chan->mode = L2CAP_MODE_LE_FLOWCTL; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci chan->state = BT_BOUND; 1738c2ecf20Sopenharmony_ci sk->sk_state = BT_BOUND; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cidone: 1768c2ecf20Sopenharmony_ci release_sock(sk); 1778c2ecf20Sopenharmony_ci return err; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic void l2cap_sock_init_pid(struct sock *sk) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* Only L2CAP_MODE_EXT_FLOWCTL ever need to access the PID in order to 1858c2ecf20Sopenharmony_ci * group the channels being requested. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci if (chan->mode != L2CAP_MODE_EXT_FLOWCTL) 1888c2ecf20Sopenharmony_ci return; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci spin_lock(&sk->sk_peer_lock); 1918c2ecf20Sopenharmony_ci sk->sk_peer_pid = get_pid(task_tgid(current)); 1928c2ecf20Sopenharmony_ci spin_unlock(&sk->sk_peer_lock); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, 1968c2ecf20Sopenharmony_ci int alen, int flags) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 1998c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 2008c2ecf20Sopenharmony_ci struct sockaddr_l2 la; 2018c2ecf20Sopenharmony_ci int len, err = 0; 2028c2ecf20Sopenharmony_ci bool zapped; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci BT_DBG("sk %p", sk); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci lock_sock(sk); 2078c2ecf20Sopenharmony_ci zapped = sock_flag(sk, SOCK_ZAPPED); 2088c2ecf20Sopenharmony_ci release_sock(sk); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (zapped) 2118c2ecf20Sopenharmony_ci return -EINVAL; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (!addr || alen < offsetofend(struct sockaddr, sa_family) || 2148c2ecf20Sopenharmony_ci addr->sa_family != AF_BLUETOOTH) 2158c2ecf20Sopenharmony_ci return -EINVAL; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci memset(&la, 0, sizeof(la)); 2188c2ecf20Sopenharmony_ci len = min_t(unsigned int, sizeof(la), alen); 2198c2ecf20Sopenharmony_ci memcpy(&la, addr, len); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (la.l2_cid && la.l2_psm) 2228c2ecf20Sopenharmony_ci return -EINVAL; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (!bdaddr_type_is_valid(la.l2_bdaddr_type)) 2258c2ecf20Sopenharmony_ci return -EINVAL; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* Check that the socket wasn't bound to something that 2288c2ecf20Sopenharmony_ci * conflicts with the address given to connect(). If chan->src 2298c2ecf20Sopenharmony_ci * is BDADDR_ANY it means bind() was never used, in which case 2308c2ecf20Sopenharmony_ci * chan->src_type and la.l2_bdaddr_type do not need to match. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) && 2338c2ecf20Sopenharmony_ci bdaddr_type_is_le(la.l2_bdaddr_type)) { 2348c2ecf20Sopenharmony_ci /* Old user space versions will try to incorrectly bind 2358c2ecf20Sopenharmony_ci * the ATT socket using BDADDR_BREDR. We need to accept 2368c2ecf20Sopenharmony_ci * this and fix up the source address type only when 2378c2ecf20Sopenharmony_ci * both the source CID and destination CID indicate 2388c2ecf20Sopenharmony_ci * ATT. Anything else is an invalid combination. 2398c2ecf20Sopenharmony_ci */ 2408c2ecf20Sopenharmony_ci if (chan->scid != L2CAP_CID_ATT || 2418c2ecf20Sopenharmony_ci la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) 2428c2ecf20Sopenharmony_ci return -EINVAL; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* We don't have the hdev available here to make a 2458c2ecf20Sopenharmony_ci * better decision on random vs public, but since all 2468c2ecf20Sopenharmony_ci * user space versions that exhibit this issue anyway do 2478c2ecf20Sopenharmony_ci * not support random local addresses assuming public 2488c2ecf20Sopenharmony_ci * here is good enough. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci chan->src_type = BDADDR_LE_PUBLIC; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (chan->src_type != BDADDR_BREDR && la.l2_bdaddr_type == BDADDR_BREDR) 2548c2ecf20Sopenharmony_ci return -EINVAL; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (bdaddr_type_is_le(la.l2_bdaddr_type)) { 2578c2ecf20Sopenharmony_ci /* We only allow ATT user space socket */ 2588c2ecf20Sopenharmony_ci if (la.l2_cid && 2598c2ecf20Sopenharmony_ci la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) 2608c2ecf20Sopenharmony_ci return -EINVAL; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Use L2CAP_MODE_LE_FLOWCTL (CoC) in case of LE address and 2648c2ecf20Sopenharmony_ci * L2CAP_MODE_EXT_FLOWCTL (ECRED) has not been set. 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_ci if (chan->psm && bdaddr_type_is_le(chan->src_type) && 2678c2ecf20Sopenharmony_ci chan->mode != L2CAP_MODE_EXT_FLOWCTL) 2688c2ecf20Sopenharmony_ci chan->mode = L2CAP_MODE_LE_FLOWCTL; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci l2cap_sock_init_pid(sk); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), 2738c2ecf20Sopenharmony_ci &la.l2_bdaddr, la.l2_bdaddr_type); 2748c2ecf20Sopenharmony_ci if (err) 2758c2ecf20Sopenharmony_ci return err; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci lock_sock(sk); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci err = bt_sock_wait_state(sk, BT_CONNECTED, 2808c2ecf20Sopenharmony_ci sock_sndtimeo(sk, flags & O_NONBLOCK)); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci release_sock(sk); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return err; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int l2cap_sock_listen(struct socket *sock, int backlog) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 2908c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 2918c2ecf20Sopenharmony_ci int err = 0; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci BT_DBG("sk %p backlog %d", sk, backlog); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci lock_sock(sk); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (sk->sk_state != BT_BOUND) { 2988c2ecf20Sopenharmony_ci err = -EBADFD; 2998c2ecf20Sopenharmony_ci goto done; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) { 3038c2ecf20Sopenharmony_ci err = -EINVAL; 3048c2ecf20Sopenharmony_ci goto done; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci switch (chan->mode) { 3088c2ecf20Sopenharmony_ci case L2CAP_MODE_BASIC: 3098c2ecf20Sopenharmony_ci case L2CAP_MODE_LE_FLOWCTL: 3108c2ecf20Sopenharmony_ci break; 3118c2ecf20Sopenharmony_ci case L2CAP_MODE_EXT_FLOWCTL: 3128c2ecf20Sopenharmony_ci if (!enable_ecred) { 3138c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 3148c2ecf20Sopenharmony_ci goto done; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci break; 3178c2ecf20Sopenharmony_ci case L2CAP_MODE_ERTM: 3188c2ecf20Sopenharmony_ci case L2CAP_MODE_STREAMING: 3198c2ecf20Sopenharmony_ci if (!disable_ertm) 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci fallthrough; 3228c2ecf20Sopenharmony_ci default: 3238c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 3248c2ecf20Sopenharmony_ci goto done; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci l2cap_sock_init_pid(sk); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci sk->sk_max_ack_backlog = backlog; 3308c2ecf20Sopenharmony_ci sk->sk_ack_backlog = 0; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Listening channels need to use nested locking in order not to 3338c2ecf20Sopenharmony_ci * cause lockdep warnings when the created child channels end up 3348c2ecf20Sopenharmony_ci * being locked in the same thread as the parent channel. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci atomic_set(&chan->nesting, L2CAP_NESTING_PARENT); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci chan->state = BT_LISTEN; 3398c2ecf20Sopenharmony_ci sk->sk_state = BT_LISTEN; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cidone: 3428c2ecf20Sopenharmony_ci release_sock(sk); 3438c2ecf20Sopenharmony_ci return err; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int l2cap_sock_accept(struct socket *sock, struct socket *newsock, 3478c2ecf20Sopenharmony_ci int flags, bool kern) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci DEFINE_WAIT_FUNC(wait, woken_wake_function); 3508c2ecf20Sopenharmony_ci struct sock *sk = sock->sk, *nsk; 3518c2ecf20Sopenharmony_ci long timeo; 3528c2ecf20Sopenharmony_ci int err = 0; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci lock_sock_nested(sk, L2CAP_NESTING_PARENT); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci BT_DBG("sk %p timeo %ld", sk, timeo); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Wait for an incoming connection. (wake-one). */ 3618c2ecf20Sopenharmony_ci add_wait_queue_exclusive(sk_sleep(sk), &wait); 3628c2ecf20Sopenharmony_ci while (1) { 3638c2ecf20Sopenharmony_ci if (sk->sk_state != BT_LISTEN) { 3648c2ecf20Sopenharmony_ci err = -EBADFD; 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci nsk = bt_accept_dequeue(sk, newsock); 3698c2ecf20Sopenharmony_ci if (nsk) 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (!timeo) { 3738c2ecf20Sopenharmony_ci err = -EAGAIN; 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (signal_pending(current)) { 3788c2ecf20Sopenharmony_ci err = sock_intr_errno(timeo); 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci release_sock(sk); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci lock_sock_nested(sk, L2CAP_NESTING_PARENT); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (err) 3918c2ecf20Sopenharmony_ci goto done; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci newsock->state = SS_CONNECTED; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci BT_DBG("new socket %p", nsk); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cidone: 3988c2ecf20Sopenharmony_ci release_sock(sk); 3998c2ecf20Sopenharmony_ci return err; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, 4038c2ecf20Sopenharmony_ci int peer) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; 4068c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 4078c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci BT_DBG("sock %p, sk %p", sock, sk); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (peer && sk->sk_state != BT_CONNECTED && 4128c2ecf20Sopenharmony_ci sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2 && 4138c2ecf20Sopenharmony_ci sk->sk_state != BT_CONFIG) 4148c2ecf20Sopenharmony_ci return -ENOTCONN; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci memset(la, 0, sizeof(struct sockaddr_l2)); 4178c2ecf20Sopenharmony_ci addr->sa_family = AF_BLUETOOTH; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci la->l2_psm = chan->psm; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (peer) { 4228c2ecf20Sopenharmony_ci bacpy(&la->l2_bdaddr, &chan->dst); 4238c2ecf20Sopenharmony_ci la->l2_cid = cpu_to_le16(chan->dcid); 4248c2ecf20Sopenharmony_ci la->l2_bdaddr_type = chan->dst_type; 4258c2ecf20Sopenharmony_ci } else { 4268c2ecf20Sopenharmony_ci bacpy(&la->l2_bdaddr, &chan->src); 4278c2ecf20Sopenharmony_ci la->l2_cid = cpu_to_le16(chan->scid); 4288c2ecf20Sopenharmony_ci la->l2_bdaddr_type = chan->src_type; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci return sizeof(struct sockaddr_l2); 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic int l2cap_get_mode(struct l2cap_chan *chan) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci switch (chan->mode) { 4378c2ecf20Sopenharmony_ci case L2CAP_MODE_BASIC: 4388c2ecf20Sopenharmony_ci return BT_MODE_BASIC; 4398c2ecf20Sopenharmony_ci case L2CAP_MODE_ERTM: 4408c2ecf20Sopenharmony_ci return BT_MODE_ERTM; 4418c2ecf20Sopenharmony_ci case L2CAP_MODE_STREAMING: 4428c2ecf20Sopenharmony_ci return BT_MODE_STREAMING; 4438c2ecf20Sopenharmony_ci case L2CAP_MODE_LE_FLOWCTL: 4448c2ecf20Sopenharmony_ci return BT_MODE_LE_FLOWCTL; 4458c2ecf20Sopenharmony_ci case L2CAP_MODE_EXT_FLOWCTL: 4468c2ecf20Sopenharmony_ci return BT_MODE_EXT_FLOWCTL; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci return -EINVAL; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic int l2cap_sock_getsockopt_old(struct socket *sock, int optname, 4538c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 4568c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 4578c2ecf20Sopenharmony_ci struct l2cap_options opts; 4588c2ecf20Sopenharmony_ci struct l2cap_conninfo cinfo; 4598c2ecf20Sopenharmony_ci int len, err = 0; 4608c2ecf20Sopenharmony_ci u32 opt; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci BT_DBG("sk %p", sk); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (get_user(len, optlen)) 4658c2ecf20Sopenharmony_ci return -EFAULT; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci lock_sock(sk); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci switch (optname) { 4708c2ecf20Sopenharmony_ci case L2CAP_OPTIONS: 4718c2ecf20Sopenharmony_ci /* LE sockets should use BT_SNDMTU/BT_RCVMTU, but since 4728c2ecf20Sopenharmony_ci * legacy ATT code depends on getsockopt for 4738c2ecf20Sopenharmony_ci * L2CAP_OPTIONS we need to let this pass. 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ci if (bdaddr_type_is_le(chan->src_type) && 4768c2ecf20Sopenharmony_ci chan->scid != L2CAP_CID_ATT) { 4778c2ecf20Sopenharmony_ci err = -EINVAL; 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* Only BR/EDR modes are supported here */ 4828c2ecf20Sopenharmony_ci switch (chan->mode) { 4838c2ecf20Sopenharmony_ci case L2CAP_MODE_BASIC: 4848c2ecf20Sopenharmony_ci case L2CAP_MODE_ERTM: 4858c2ecf20Sopenharmony_ci case L2CAP_MODE_STREAMING: 4868c2ecf20Sopenharmony_ci break; 4878c2ecf20Sopenharmony_ci default: 4888c2ecf20Sopenharmony_ci err = -EINVAL; 4898c2ecf20Sopenharmony_ci break; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (err < 0) 4938c2ecf20Sopenharmony_ci break; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci memset(&opts, 0, sizeof(opts)); 4968c2ecf20Sopenharmony_ci opts.imtu = chan->imtu; 4978c2ecf20Sopenharmony_ci opts.omtu = chan->omtu; 4988c2ecf20Sopenharmony_ci opts.flush_to = chan->flush_to; 4998c2ecf20Sopenharmony_ci opts.mode = chan->mode; 5008c2ecf20Sopenharmony_ci opts.fcs = chan->fcs; 5018c2ecf20Sopenharmony_ci opts.max_tx = chan->max_tx; 5028c2ecf20Sopenharmony_ci opts.txwin_size = chan->tx_win; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci BT_DBG("mode 0x%2.2x", chan->mode); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci len = min_t(unsigned int, len, sizeof(opts)); 5078c2ecf20Sopenharmony_ci if (copy_to_user(optval, (char *) &opts, len)) 5088c2ecf20Sopenharmony_ci err = -EFAULT; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci break; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci case L2CAP_LM: 5138c2ecf20Sopenharmony_ci switch (chan->sec_level) { 5148c2ecf20Sopenharmony_ci case BT_SECURITY_LOW: 5158c2ecf20Sopenharmony_ci opt = L2CAP_LM_AUTH; 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci case BT_SECURITY_MEDIUM: 5188c2ecf20Sopenharmony_ci opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT; 5198c2ecf20Sopenharmony_ci break; 5208c2ecf20Sopenharmony_ci case BT_SECURITY_HIGH: 5218c2ecf20Sopenharmony_ci opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | 5228c2ecf20Sopenharmony_ci L2CAP_LM_SECURE; 5238c2ecf20Sopenharmony_ci break; 5248c2ecf20Sopenharmony_ci case BT_SECURITY_FIPS: 5258c2ecf20Sopenharmony_ci opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | 5268c2ecf20Sopenharmony_ci L2CAP_LM_SECURE | L2CAP_LM_FIPS; 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci default: 5298c2ecf20Sopenharmony_ci opt = 0; 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (test_bit(FLAG_ROLE_SWITCH, &chan->flags)) 5348c2ecf20Sopenharmony_ci opt |= L2CAP_LM_MASTER; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) 5378c2ecf20Sopenharmony_ci opt |= L2CAP_LM_RELIABLE; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (put_user(opt, (u32 __user *) optval)) 5408c2ecf20Sopenharmony_ci err = -EFAULT; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci case L2CAP_CONNINFO: 5458c2ecf20Sopenharmony_ci if (sk->sk_state != BT_CONNECTED && 5468c2ecf20Sopenharmony_ci !(sk->sk_state == BT_CONNECT2 && 5478c2ecf20Sopenharmony_ci test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) { 5488c2ecf20Sopenharmony_ci err = -ENOTCONN; 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci memset(&cinfo, 0, sizeof(cinfo)); 5538c2ecf20Sopenharmony_ci cinfo.hci_handle = chan->conn->hcon->handle; 5548c2ecf20Sopenharmony_ci memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci len = min_t(unsigned int, len, sizeof(cinfo)); 5578c2ecf20Sopenharmony_ci if (copy_to_user(optval, (char *) &cinfo, len)) 5588c2ecf20Sopenharmony_ci err = -EFAULT; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci default: 5638c2ecf20Sopenharmony_ci err = -ENOPROTOOPT; 5648c2ecf20Sopenharmony_ci break; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci release_sock(sk); 5688c2ecf20Sopenharmony_ci return err; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, 5728c2ecf20Sopenharmony_ci char __user *optval, int __user *optlen) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 5758c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 5768c2ecf20Sopenharmony_ci struct bt_security sec; 5778c2ecf20Sopenharmony_ci struct bt_power pwr; 5788c2ecf20Sopenharmony_ci u32 phys; 5798c2ecf20Sopenharmony_ci int len, mode, err = 0; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci BT_DBG("sk %p", sk); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (level == SOL_L2CAP) 5848c2ecf20Sopenharmony_ci return l2cap_sock_getsockopt_old(sock, optname, optval, optlen); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (level != SOL_BLUETOOTH) 5878c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (get_user(len, optlen)) 5908c2ecf20Sopenharmony_ci return -EFAULT; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci lock_sock(sk); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci switch (optname) { 5958c2ecf20Sopenharmony_ci case BT_SECURITY: 5968c2ecf20Sopenharmony_ci if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED && 5978c2ecf20Sopenharmony_ci chan->chan_type != L2CAP_CHAN_FIXED && 5988c2ecf20Sopenharmony_ci chan->chan_type != L2CAP_CHAN_RAW) { 5998c2ecf20Sopenharmony_ci err = -EINVAL; 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci memset(&sec, 0, sizeof(sec)); 6048c2ecf20Sopenharmony_ci if (chan->conn) { 6058c2ecf20Sopenharmony_ci sec.level = chan->conn->hcon->sec_level; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (sk->sk_state == BT_CONNECTED) 6088c2ecf20Sopenharmony_ci sec.key_size = chan->conn->hcon->enc_key_size; 6098c2ecf20Sopenharmony_ci } else { 6108c2ecf20Sopenharmony_ci sec.level = chan->sec_level; 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci len = min_t(unsigned int, len, sizeof(sec)); 6148c2ecf20Sopenharmony_ci if (copy_to_user(optval, (char *) &sec, len)) 6158c2ecf20Sopenharmony_ci err = -EFAULT; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci case BT_DEFER_SETUP: 6208c2ecf20Sopenharmony_ci if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { 6218c2ecf20Sopenharmony_ci err = -EINVAL; 6228c2ecf20Sopenharmony_ci break; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), 6268c2ecf20Sopenharmony_ci (u32 __user *) optval)) 6278c2ecf20Sopenharmony_ci err = -EFAULT; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci break; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci case BT_FLUSHABLE: 6328c2ecf20Sopenharmony_ci if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags), 6338c2ecf20Sopenharmony_ci (u32 __user *) optval)) 6348c2ecf20Sopenharmony_ci err = -EFAULT; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci break; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci case BT_POWER: 6398c2ecf20Sopenharmony_ci if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM 6408c2ecf20Sopenharmony_ci && sk->sk_type != SOCK_RAW) { 6418c2ecf20Sopenharmony_ci err = -EINVAL; 6428c2ecf20Sopenharmony_ci break; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci len = min_t(unsigned int, len, sizeof(pwr)); 6488c2ecf20Sopenharmony_ci if (copy_to_user(optval, (char *) &pwr, len)) 6498c2ecf20Sopenharmony_ci err = -EFAULT; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci case BT_CHANNEL_POLICY: 6548c2ecf20Sopenharmony_ci if (put_user(chan->chan_policy, (u32 __user *) optval)) 6558c2ecf20Sopenharmony_ci err = -EFAULT; 6568c2ecf20Sopenharmony_ci break; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci case BT_SNDMTU: 6598c2ecf20Sopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) { 6608c2ecf20Sopenharmony_ci err = -EINVAL; 6618c2ecf20Sopenharmony_ci break; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (sk->sk_state != BT_CONNECTED) { 6658c2ecf20Sopenharmony_ci err = -ENOTCONN; 6668c2ecf20Sopenharmony_ci break; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (put_user(chan->omtu, (u16 __user *) optval)) 6708c2ecf20Sopenharmony_ci err = -EFAULT; 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci case BT_RCVMTU: 6748c2ecf20Sopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) { 6758c2ecf20Sopenharmony_ci err = -EINVAL; 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (put_user(chan->imtu, (u16 __user *) optval)) 6808c2ecf20Sopenharmony_ci err = -EFAULT; 6818c2ecf20Sopenharmony_ci break; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci case BT_PHY: 6848c2ecf20Sopenharmony_ci if (sk->sk_state != BT_CONNECTED) { 6858c2ecf20Sopenharmony_ci err = -ENOTCONN; 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci phys = hci_conn_get_phy(chan->conn->hcon); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci if (put_user(phys, (u32 __user *) optval)) 6928c2ecf20Sopenharmony_ci err = -EFAULT; 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci case BT_MODE: 6968c2ecf20Sopenharmony_ci if (!enable_ecred) { 6978c2ecf20Sopenharmony_ci err = -ENOPROTOOPT; 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { 7028c2ecf20Sopenharmony_ci err = -EINVAL; 7038c2ecf20Sopenharmony_ci break; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci mode = l2cap_get_mode(chan); 7078c2ecf20Sopenharmony_ci if (mode < 0) { 7088c2ecf20Sopenharmony_ci err = mode; 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (put_user(mode, (u8 __user *) optval)) 7138c2ecf20Sopenharmony_ci err = -EFAULT; 7148c2ecf20Sopenharmony_ci break; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci default: 7178c2ecf20Sopenharmony_ci err = -ENOPROTOOPT; 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci release_sock(sk); 7228c2ecf20Sopenharmony_ci return err; 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_cistatic bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci switch (chan->scid) { 7288c2ecf20Sopenharmony_ci case L2CAP_CID_ATT: 7298c2ecf20Sopenharmony_ci if (mtu < L2CAP_LE_MIN_MTU) 7308c2ecf20Sopenharmony_ci return false; 7318c2ecf20Sopenharmony_ci break; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci default: 7348c2ecf20Sopenharmony_ci if (mtu < L2CAP_DEFAULT_MIN_MTU) 7358c2ecf20Sopenharmony_ci return false; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return true; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic int l2cap_sock_setsockopt_old(struct socket *sock, int optname, 7428c2ecf20Sopenharmony_ci sockptr_t optval, unsigned int optlen) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 7458c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 7468c2ecf20Sopenharmony_ci struct l2cap_options opts; 7478c2ecf20Sopenharmony_ci int len, err = 0; 7488c2ecf20Sopenharmony_ci u32 opt; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci BT_DBG("sk %p", sk); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci lock_sock(sk); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci switch (optname) { 7558c2ecf20Sopenharmony_ci case L2CAP_OPTIONS: 7568c2ecf20Sopenharmony_ci if (bdaddr_type_is_le(chan->src_type)) { 7578c2ecf20Sopenharmony_ci err = -EINVAL; 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci if (sk->sk_state == BT_CONNECTED) { 7628c2ecf20Sopenharmony_ci err = -EINVAL; 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci opts.imtu = chan->imtu; 7678c2ecf20Sopenharmony_ci opts.omtu = chan->omtu; 7688c2ecf20Sopenharmony_ci opts.flush_to = chan->flush_to; 7698c2ecf20Sopenharmony_ci opts.mode = chan->mode; 7708c2ecf20Sopenharmony_ci opts.fcs = chan->fcs; 7718c2ecf20Sopenharmony_ci opts.max_tx = chan->max_tx; 7728c2ecf20Sopenharmony_ci opts.txwin_size = chan->tx_win; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci len = min_t(unsigned int, sizeof(opts), optlen); 7758c2ecf20Sopenharmony_ci if (copy_from_sockptr(&opts, optval, len)) { 7768c2ecf20Sopenharmony_ci err = -EFAULT; 7778c2ecf20Sopenharmony_ci break; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) { 7818c2ecf20Sopenharmony_ci err = -EINVAL; 7828c2ecf20Sopenharmony_ci break; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (!l2cap_valid_mtu(chan, opts.imtu)) { 7868c2ecf20Sopenharmony_ci err = -EINVAL; 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci /* Only BR/EDR modes are supported here */ 7918c2ecf20Sopenharmony_ci switch (opts.mode) { 7928c2ecf20Sopenharmony_ci case L2CAP_MODE_BASIC: 7938c2ecf20Sopenharmony_ci clear_bit(CONF_STATE2_DEVICE, &chan->conf_state); 7948c2ecf20Sopenharmony_ci break; 7958c2ecf20Sopenharmony_ci case L2CAP_MODE_ERTM: 7968c2ecf20Sopenharmony_ci case L2CAP_MODE_STREAMING: 7978c2ecf20Sopenharmony_ci if (!disable_ertm) 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci fallthrough; 8008c2ecf20Sopenharmony_ci default: 8018c2ecf20Sopenharmony_ci err = -EINVAL; 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (err < 0) 8068c2ecf20Sopenharmony_ci break; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci chan->mode = opts.mode; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci BT_DBG("mode 0x%2.2x", chan->mode); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci chan->imtu = opts.imtu; 8138c2ecf20Sopenharmony_ci chan->omtu = opts.omtu; 8148c2ecf20Sopenharmony_ci chan->fcs = opts.fcs; 8158c2ecf20Sopenharmony_ci chan->max_tx = opts.max_tx; 8168c2ecf20Sopenharmony_ci chan->tx_win = opts.txwin_size; 8178c2ecf20Sopenharmony_ci chan->flush_to = opts.flush_to; 8188c2ecf20Sopenharmony_ci break; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci case L2CAP_LM: 8218c2ecf20Sopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(u32))) { 8228c2ecf20Sopenharmony_ci err = -EFAULT; 8238c2ecf20Sopenharmony_ci break; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (opt & L2CAP_LM_FIPS) { 8278c2ecf20Sopenharmony_ci err = -EINVAL; 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci if (opt & L2CAP_LM_AUTH) 8328c2ecf20Sopenharmony_ci chan->sec_level = BT_SECURITY_LOW; 8338c2ecf20Sopenharmony_ci if (opt & L2CAP_LM_ENCRYPT) 8348c2ecf20Sopenharmony_ci chan->sec_level = BT_SECURITY_MEDIUM; 8358c2ecf20Sopenharmony_ci if (opt & L2CAP_LM_SECURE) 8368c2ecf20Sopenharmony_ci chan->sec_level = BT_SECURITY_HIGH; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (opt & L2CAP_LM_MASTER) 8398c2ecf20Sopenharmony_ci set_bit(FLAG_ROLE_SWITCH, &chan->flags); 8408c2ecf20Sopenharmony_ci else 8418c2ecf20Sopenharmony_ci clear_bit(FLAG_ROLE_SWITCH, &chan->flags); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (opt & L2CAP_LM_RELIABLE) 8448c2ecf20Sopenharmony_ci set_bit(FLAG_FORCE_RELIABLE, &chan->flags); 8458c2ecf20Sopenharmony_ci else 8468c2ecf20Sopenharmony_ci clear_bit(FLAG_FORCE_RELIABLE, &chan->flags); 8478c2ecf20Sopenharmony_ci break; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci default: 8508c2ecf20Sopenharmony_ci err = -ENOPROTOOPT; 8518c2ecf20Sopenharmony_ci break; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci release_sock(sk); 8558c2ecf20Sopenharmony_ci return err; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic int l2cap_set_mode(struct l2cap_chan *chan, u8 mode) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci switch (mode) { 8618c2ecf20Sopenharmony_ci case BT_MODE_BASIC: 8628c2ecf20Sopenharmony_ci if (bdaddr_type_is_le(chan->src_type)) 8638c2ecf20Sopenharmony_ci return -EINVAL; 8648c2ecf20Sopenharmony_ci mode = L2CAP_MODE_BASIC; 8658c2ecf20Sopenharmony_ci clear_bit(CONF_STATE2_DEVICE, &chan->conf_state); 8668c2ecf20Sopenharmony_ci break; 8678c2ecf20Sopenharmony_ci case BT_MODE_ERTM: 8688c2ecf20Sopenharmony_ci if (!disable_ertm || bdaddr_type_is_le(chan->src_type)) 8698c2ecf20Sopenharmony_ci return -EINVAL; 8708c2ecf20Sopenharmony_ci mode = L2CAP_MODE_ERTM; 8718c2ecf20Sopenharmony_ci break; 8728c2ecf20Sopenharmony_ci case BT_MODE_STREAMING: 8738c2ecf20Sopenharmony_ci if (!disable_ertm || bdaddr_type_is_le(chan->src_type)) 8748c2ecf20Sopenharmony_ci return -EINVAL; 8758c2ecf20Sopenharmony_ci mode = L2CAP_MODE_STREAMING; 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci case BT_MODE_LE_FLOWCTL: 8788c2ecf20Sopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) 8798c2ecf20Sopenharmony_ci return -EINVAL; 8808c2ecf20Sopenharmony_ci mode = L2CAP_MODE_LE_FLOWCTL; 8818c2ecf20Sopenharmony_ci break; 8828c2ecf20Sopenharmony_ci case BT_MODE_EXT_FLOWCTL: 8838c2ecf20Sopenharmony_ci /* TODO: Add support for ECRED PDUs to BR/EDR */ 8848c2ecf20Sopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) 8858c2ecf20Sopenharmony_ci return -EINVAL; 8868c2ecf20Sopenharmony_ci mode = L2CAP_MODE_EXT_FLOWCTL; 8878c2ecf20Sopenharmony_ci break; 8888c2ecf20Sopenharmony_ci default: 8898c2ecf20Sopenharmony_ci return -EINVAL; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci chan->mode = mode; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return 0; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, 8988c2ecf20Sopenharmony_ci sockptr_t optval, unsigned int optlen) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 9018c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 9028c2ecf20Sopenharmony_ci struct bt_security sec; 9038c2ecf20Sopenharmony_ci struct bt_power pwr; 9048c2ecf20Sopenharmony_ci struct l2cap_conn *conn; 9058c2ecf20Sopenharmony_ci int len, err = 0; 9068c2ecf20Sopenharmony_ci u32 opt; 9078c2ecf20Sopenharmony_ci u16 mtu; 9088c2ecf20Sopenharmony_ci u8 mode; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci BT_DBG("sk %p", sk); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci if (level == SOL_L2CAP) 9138c2ecf20Sopenharmony_ci return l2cap_sock_setsockopt_old(sock, optname, optval, optlen); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (level != SOL_BLUETOOTH) 9168c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci lock_sock(sk); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci switch (optname) { 9218c2ecf20Sopenharmony_ci case BT_SECURITY: 9228c2ecf20Sopenharmony_ci if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED && 9238c2ecf20Sopenharmony_ci chan->chan_type != L2CAP_CHAN_FIXED && 9248c2ecf20Sopenharmony_ci chan->chan_type != L2CAP_CHAN_RAW) { 9258c2ecf20Sopenharmony_ci err = -EINVAL; 9268c2ecf20Sopenharmony_ci break; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci sec.level = BT_SECURITY_LOW; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci len = min_t(unsigned int, sizeof(sec), optlen); 9328c2ecf20Sopenharmony_ci if (copy_from_sockptr(&sec, optval, len)) { 9338c2ecf20Sopenharmony_ci err = -EFAULT; 9348c2ecf20Sopenharmony_ci break; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (sec.level < BT_SECURITY_LOW || 9388c2ecf20Sopenharmony_ci sec.level > BT_SECURITY_FIPS) { 9398c2ecf20Sopenharmony_ci err = -EINVAL; 9408c2ecf20Sopenharmony_ci break; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci chan->sec_level = sec.level; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if (!chan->conn) 9468c2ecf20Sopenharmony_ci break; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci conn = chan->conn; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci /* change security for LE channels */ 9518c2ecf20Sopenharmony_ci if (chan->scid == L2CAP_CID_ATT) { 9528c2ecf20Sopenharmony_ci if (smp_conn_security(conn->hcon, sec.level)) { 9538c2ecf20Sopenharmony_ci err = -EINVAL; 9548c2ecf20Sopenharmony_ci break; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci set_bit(FLAG_PENDING_SECURITY, &chan->flags); 9588c2ecf20Sopenharmony_ci sk->sk_state = BT_CONFIG; 9598c2ecf20Sopenharmony_ci chan->state = BT_CONFIG; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* or for ACL link */ 9628c2ecf20Sopenharmony_ci } else if ((sk->sk_state == BT_CONNECT2 && 9638c2ecf20Sopenharmony_ci test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) || 9648c2ecf20Sopenharmony_ci sk->sk_state == BT_CONNECTED) { 9658c2ecf20Sopenharmony_ci if (!l2cap_chan_check_security(chan, true)) 9668c2ecf20Sopenharmony_ci set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); 9678c2ecf20Sopenharmony_ci else 9688c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 9698c2ecf20Sopenharmony_ci } else { 9708c2ecf20Sopenharmony_ci err = -EINVAL; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci break; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci case BT_DEFER_SETUP: 9758c2ecf20Sopenharmony_ci if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { 9768c2ecf20Sopenharmony_ci err = -EINVAL; 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(u32))) { 9818c2ecf20Sopenharmony_ci err = -EFAULT; 9828c2ecf20Sopenharmony_ci break; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (opt) { 9868c2ecf20Sopenharmony_ci set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); 9878c2ecf20Sopenharmony_ci set_bit(FLAG_DEFER_SETUP, &chan->flags); 9888c2ecf20Sopenharmony_ci } else { 9898c2ecf20Sopenharmony_ci clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); 9908c2ecf20Sopenharmony_ci clear_bit(FLAG_DEFER_SETUP, &chan->flags); 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci break; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci case BT_FLUSHABLE: 9958c2ecf20Sopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(u32))) { 9968c2ecf20Sopenharmony_ci err = -EFAULT; 9978c2ecf20Sopenharmony_ci break; 9988c2ecf20Sopenharmony_ci } 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci if (opt > BT_FLUSHABLE_ON) { 10018c2ecf20Sopenharmony_ci err = -EINVAL; 10028c2ecf20Sopenharmony_ci break; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci if (opt == BT_FLUSHABLE_OFF) { 10068c2ecf20Sopenharmony_ci conn = chan->conn; 10078c2ecf20Sopenharmony_ci /* proceed further only when we have l2cap_conn and 10088c2ecf20Sopenharmony_ci No Flush support in the LM */ 10098c2ecf20Sopenharmony_ci if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) { 10108c2ecf20Sopenharmony_ci err = -EINVAL; 10118c2ecf20Sopenharmony_ci break; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (opt) 10168c2ecf20Sopenharmony_ci set_bit(FLAG_FLUSHABLE, &chan->flags); 10178c2ecf20Sopenharmony_ci else 10188c2ecf20Sopenharmony_ci clear_bit(FLAG_FLUSHABLE, &chan->flags); 10198c2ecf20Sopenharmony_ci break; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci case BT_POWER: 10228c2ecf20Sopenharmony_ci if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED && 10238c2ecf20Sopenharmony_ci chan->chan_type != L2CAP_CHAN_RAW) { 10248c2ecf20Sopenharmony_ci err = -EINVAL; 10258c2ecf20Sopenharmony_ci break; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci pwr.force_active = BT_POWER_FORCE_ACTIVE_ON; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci len = min_t(unsigned int, sizeof(pwr), optlen); 10318c2ecf20Sopenharmony_ci if (copy_from_sockptr(&pwr, optval, len)) { 10328c2ecf20Sopenharmony_ci err = -EFAULT; 10338c2ecf20Sopenharmony_ci break; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (pwr.force_active) 10378c2ecf20Sopenharmony_ci set_bit(FLAG_FORCE_ACTIVE, &chan->flags); 10388c2ecf20Sopenharmony_ci else 10398c2ecf20Sopenharmony_ci clear_bit(FLAG_FORCE_ACTIVE, &chan->flags); 10408c2ecf20Sopenharmony_ci break; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci case BT_CHANNEL_POLICY: 10438c2ecf20Sopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(u32))) { 10448c2ecf20Sopenharmony_ci err = -EFAULT; 10458c2ecf20Sopenharmony_ci break; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) { 10498c2ecf20Sopenharmony_ci err = -EINVAL; 10508c2ecf20Sopenharmony_ci break; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (chan->mode != L2CAP_MODE_ERTM && 10548c2ecf20Sopenharmony_ci chan->mode != L2CAP_MODE_STREAMING) { 10558c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 10568c2ecf20Sopenharmony_ci break; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci chan->chan_policy = (u8) opt; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci if (sk->sk_state == BT_CONNECTED && 10628c2ecf20Sopenharmony_ci chan->move_role == L2CAP_MOVE_ROLE_NONE) 10638c2ecf20Sopenharmony_ci l2cap_move_start(chan); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci case BT_SNDMTU: 10688c2ecf20Sopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) { 10698c2ecf20Sopenharmony_ci err = -EINVAL; 10708c2ecf20Sopenharmony_ci break; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci /* Setting is not supported as it's the remote side that 10748c2ecf20Sopenharmony_ci * decides this. 10758c2ecf20Sopenharmony_ci */ 10768c2ecf20Sopenharmony_ci err = -EPERM; 10778c2ecf20Sopenharmony_ci break; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci case BT_RCVMTU: 10808c2ecf20Sopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) { 10818c2ecf20Sopenharmony_ci err = -EINVAL; 10828c2ecf20Sopenharmony_ci break; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (chan->mode == L2CAP_MODE_LE_FLOWCTL && 10868c2ecf20Sopenharmony_ci sk->sk_state == BT_CONNECTED) { 10878c2ecf20Sopenharmony_ci err = -EISCONN; 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci if (copy_from_sockptr(&mtu, optval, sizeof(u16))) { 10928c2ecf20Sopenharmony_ci err = -EFAULT; 10938c2ecf20Sopenharmony_ci break; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (chan->mode == L2CAP_MODE_EXT_FLOWCTL && 10978c2ecf20Sopenharmony_ci sk->sk_state == BT_CONNECTED) 10988c2ecf20Sopenharmony_ci err = l2cap_chan_reconfigure(chan, mtu); 10998c2ecf20Sopenharmony_ci else 11008c2ecf20Sopenharmony_ci chan->imtu = mtu; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci case BT_MODE: 11058c2ecf20Sopenharmony_ci if (!enable_ecred) { 11068c2ecf20Sopenharmony_ci err = -ENOPROTOOPT; 11078c2ecf20Sopenharmony_ci break; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci BT_DBG("sk->sk_state %u", sk->sk_state); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (sk->sk_state != BT_BOUND) { 11138c2ecf20Sopenharmony_ci err = -EINVAL; 11148c2ecf20Sopenharmony_ci break; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { 11188c2ecf20Sopenharmony_ci err = -EINVAL; 11198c2ecf20Sopenharmony_ci break; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci if (copy_from_sockptr(&mode, optval, sizeof(u8))) { 11238c2ecf20Sopenharmony_ci err = -EFAULT; 11248c2ecf20Sopenharmony_ci break; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci BT_DBG("mode %u", mode); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci err = l2cap_set_mode(chan, mode); 11308c2ecf20Sopenharmony_ci if (err) 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci BT_DBG("mode 0x%2.2x", chan->mode); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci break; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci default: 11388c2ecf20Sopenharmony_ci err = -ENOPROTOOPT; 11398c2ecf20Sopenharmony_ci break; 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci release_sock(sk); 11438c2ecf20Sopenharmony_ci return err; 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, 11478c2ecf20Sopenharmony_ci size_t len) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 11508c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 11518c2ecf20Sopenharmony_ci int err; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci BT_DBG("sock %p, sk %p", sock, sk); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci err = sock_error(sk); 11568c2ecf20Sopenharmony_ci if (err) 11578c2ecf20Sopenharmony_ci return err; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (msg->msg_flags & MSG_OOB) 11608c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (sk->sk_state != BT_CONNECTED) 11638c2ecf20Sopenharmony_ci return -ENOTCONN; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci lock_sock(sk); 11668c2ecf20Sopenharmony_ci err = bt_sock_wait_ready(sk, msg->msg_flags); 11678c2ecf20Sopenharmony_ci release_sock(sk); 11688c2ecf20Sopenharmony_ci if (err) 11698c2ecf20Sopenharmony_ci return err; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci l2cap_chan_lock(chan); 11728c2ecf20Sopenharmony_ci err = l2cap_chan_send(chan, msg, len); 11738c2ecf20Sopenharmony_ci l2cap_chan_unlock(chan); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci return err; 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_cistatic int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, 11798c2ecf20Sopenharmony_ci size_t len, int flags) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 11828c2ecf20Sopenharmony_ci struct l2cap_pinfo *pi = l2cap_pi(sk); 11838c2ecf20Sopenharmony_ci int err; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci lock_sock(sk); 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, 11888c2ecf20Sopenharmony_ci &bt_sk(sk)->flags)) { 11898c2ecf20Sopenharmony_ci if (pi->chan->mode == L2CAP_MODE_EXT_FLOWCTL) { 11908c2ecf20Sopenharmony_ci sk->sk_state = BT_CONNECTED; 11918c2ecf20Sopenharmony_ci pi->chan->state = BT_CONNECTED; 11928c2ecf20Sopenharmony_ci __l2cap_ecred_conn_rsp_defer(pi->chan); 11938c2ecf20Sopenharmony_ci } else if (bdaddr_type_is_le(pi->chan->src_type)) { 11948c2ecf20Sopenharmony_ci sk->sk_state = BT_CONNECTED; 11958c2ecf20Sopenharmony_ci pi->chan->state = BT_CONNECTED; 11968c2ecf20Sopenharmony_ci __l2cap_le_connect_rsp_defer(pi->chan); 11978c2ecf20Sopenharmony_ci } else { 11988c2ecf20Sopenharmony_ci sk->sk_state = BT_CONFIG; 11998c2ecf20Sopenharmony_ci pi->chan->state = BT_CONFIG; 12008c2ecf20Sopenharmony_ci __l2cap_connect_rsp_defer(pi->chan); 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci err = 0; 12048c2ecf20Sopenharmony_ci goto done; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci release_sock(sk); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if (sock->type == SOCK_STREAM) 12108c2ecf20Sopenharmony_ci err = bt_sock_stream_recvmsg(sock, msg, len, flags); 12118c2ecf20Sopenharmony_ci else 12128c2ecf20Sopenharmony_ci err = bt_sock_recvmsg(sock, msg, len, flags); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (pi->chan->mode != L2CAP_MODE_ERTM) 12158c2ecf20Sopenharmony_ci return err; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci /* Attempt to put pending rx data in the socket buffer */ 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci lock_sock(sk); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (!test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state)) 12228c2ecf20Sopenharmony_ci goto done; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if (pi->rx_busy_skb) { 12258c2ecf20Sopenharmony_ci if (!__sock_queue_rcv_skb(sk, pi->rx_busy_skb)) 12268c2ecf20Sopenharmony_ci pi->rx_busy_skb = NULL; 12278c2ecf20Sopenharmony_ci else 12288c2ecf20Sopenharmony_ci goto done; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci /* Restore data flow when half of the receive buffer is 12328c2ecf20Sopenharmony_ci * available. This avoids resending large numbers of 12338c2ecf20Sopenharmony_ci * frames. 12348c2ecf20Sopenharmony_ci */ 12358c2ecf20Sopenharmony_ci if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1) 12368c2ecf20Sopenharmony_ci l2cap_chan_busy(pi->chan, 0); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cidone: 12398c2ecf20Sopenharmony_ci release_sock(sk); 12408c2ecf20Sopenharmony_ci return err; 12418c2ecf20Sopenharmony_ci} 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci/* Kill socket (only if zapped and orphan) 12448c2ecf20Sopenharmony_ci * Must be called on unlocked socket, with l2cap channel lock. 12458c2ecf20Sopenharmony_ci */ 12468c2ecf20Sopenharmony_cistatic void l2cap_sock_kill(struct sock *sk) 12478c2ecf20Sopenharmony_ci{ 12488c2ecf20Sopenharmony_ci if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) 12498c2ecf20Sopenharmony_ci return; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state)); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci /* Kill poor orphan */ 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci l2cap_chan_put(l2cap_pi(sk)->chan); 12568c2ecf20Sopenharmony_ci sock_set_flag(sk, SOCK_DEAD); 12578c2ecf20Sopenharmony_ci sock_put(sk); 12588c2ecf20Sopenharmony_ci} 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan) 12618c2ecf20Sopenharmony_ci{ 12628c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 12638c2ecf20Sopenharmony_ci int err = 0; 12648c2ecf20Sopenharmony_ci int timeo = L2CAP_WAIT_ACK_POLL_PERIOD; 12658c2ecf20Sopenharmony_ci /* Timeout to prevent infinite loop */ 12668c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + L2CAP_WAIT_ACK_TIMEOUT; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci add_wait_queue(sk_sleep(sk), &wait); 12698c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 12708c2ecf20Sopenharmony_ci do { 12718c2ecf20Sopenharmony_ci BT_DBG("Waiting for %d ACKs, timeout %04d ms", 12728c2ecf20Sopenharmony_ci chan->unacked_frames, time_after(jiffies, timeout) ? 0 : 12738c2ecf20Sopenharmony_ci jiffies_to_msecs(timeout - jiffies)); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci if (!timeo) 12768c2ecf20Sopenharmony_ci timeo = L2CAP_WAIT_ACK_POLL_PERIOD; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (signal_pending(current)) { 12798c2ecf20Sopenharmony_ci err = sock_intr_errno(timeo); 12808c2ecf20Sopenharmony_ci break; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci release_sock(sk); 12848c2ecf20Sopenharmony_ci timeo = schedule_timeout(timeo); 12858c2ecf20Sopenharmony_ci lock_sock(sk); 12868c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci err = sock_error(sk); 12898c2ecf20Sopenharmony_ci if (err) 12908c2ecf20Sopenharmony_ci break; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 12938c2ecf20Sopenharmony_ci err = -ENOLINK; 12948c2ecf20Sopenharmony_ci break; 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci } while (chan->unacked_frames > 0 && 12988c2ecf20Sopenharmony_ci chan->state == BT_CONNECTED); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci set_current_state(TASK_RUNNING); 13018c2ecf20Sopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 13028c2ecf20Sopenharmony_ci return err; 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cistatic int l2cap_sock_shutdown(struct socket *sock, int how) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 13088c2ecf20Sopenharmony_ci struct l2cap_chan *chan; 13098c2ecf20Sopenharmony_ci struct l2cap_conn *conn; 13108c2ecf20Sopenharmony_ci int err = 0; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci BT_DBG("sock %p, sk %p, how %d", sock, sk, how); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* 'how' parameter is mapped to sk_shutdown as follows: 13158c2ecf20Sopenharmony_ci * SHUT_RD (0) --> RCV_SHUTDOWN (1) 13168c2ecf20Sopenharmony_ci * SHUT_WR (1) --> SEND_SHUTDOWN (2) 13178c2ecf20Sopenharmony_ci * SHUT_RDWR (2) --> SHUTDOWN_MASK (3) 13188c2ecf20Sopenharmony_ci */ 13198c2ecf20Sopenharmony_ci how++; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if (!sk) 13228c2ecf20Sopenharmony_ci return 0; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci lock_sock(sk); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci if ((sk->sk_shutdown & how) == how) 13278c2ecf20Sopenharmony_ci goto shutdown_already; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci BT_DBG("Handling sock shutdown"); 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci /* prevent sk structure from being freed whilst unlocked */ 13328c2ecf20Sopenharmony_ci sock_hold(sk); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci chan = l2cap_pi(sk)->chan; 13358c2ecf20Sopenharmony_ci /* prevent chan structure from being freed whilst unlocked */ 13368c2ecf20Sopenharmony_ci l2cap_chan_hold(chan); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (chan->mode == L2CAP_MODE_ERTM && 13418c2ecf20Sopenharmony_ci chan->unacked_frames > 0 && 13428c2ecf20Sopenharmony_ci chan->state == BT_CONNECTED) { 13438c2ecf20Sopenharmony_ci err = __l2cap_wait_ack(sk, chan); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci /* After waiting for ACKs, check whether shutdown 13468c2ecf20Sopenharmony_ci * has already been actioned to close the L2CAP 13478c2ecf20Sopenharmony_ci * link such as by l2cap_disconnection_req(). 13488c2ecf20Sopenharmony_ci */ 13498c2ecf20Sopenharmony_ci if ((sk->sk_shutdown & how) == how) 13508c2ecf20Sopenharmony_ci goto shutdown_matched; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci /* Try setting the RCV_SHUTDOWN bit, return early if SEND_SHUTDOWN 13548c2ecf20Sopenharmony_ci * is already set 13558c2ecf20Sopenharmony_ci */ 13568c2ecf20Sopenharmony_ci if ((how & RCV_SHUTDOWN) && !(sk->sk_shutdown & RCV_SHUTDOWN)) { 13578c2ecf20Sopenharmony_ci sk->sk_shutdown |= RCV_SHUTDOWN; 13588c2ecf20Sopenharmony_ci if ((sk->sk_shutdown & how) == how) 13598c2ecf20Sopenharmony_ci goto shutdown_matched; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci sk->sk_shutdown |= SEND_SHUTDOWN; 13638c2ecf20Sopenharmony_ci release_sock(sk); 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci l2cap_chan_lock(chan); 13668c2ecf20Sopenharmony_ci conn = chan->conn; 13678c2ecf20Sopenharmony_ci if (conn) 13688c2ecf20Sopenharmony_ci /* prevent conn structure from being freed */ 13698c2ecf20Sopenharmony_ci l2cap_conn_get(conn); 13708c2ecf20Sopenharmony_ci l2cap_chan_unlock(chan); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (conn) 13738c2ecf20Sopenharmony_ci /* mutex lock must be taken before l2cap_chan_lock() */ 13748c2ecf20Sopenharmony_ci mutex_lock(&conn->chan_lock); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci l2cap_chan_lock(chan); 13778c2ecf20Sopenharmony_ci l2cap_chan_close(chan, 0); 13788c2ecf20Sopenharmony_ci l2cap_chan_unlock(chan); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (conn) { 13818c2ecf20Sopenharmony_ci mutex_unlock(&conn->chan_lock); 13828c2ecf20Sopenharmony_ci l2cap_conn_put(conn); 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci lock_sock(sk); 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && 13888c2ecf20Sopenharmony_ci !(current->flags & PF_EXITING)) 13898c2ecf20Sopenharmony_ci err = bt_sock_wait_state(sk, BT_CLOSED, 13908c2ecf20Sopenharmony_ci sk->sk_lingertime); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_cishutdown_matched: 13938c2ecf20Sopenharmony_ci l2cap_chan_put(chan); 13948c2ecf20Sopenharmony_ci sock_put(sk); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cishutdown_already: 13978c2ecf20Sopenharmony_ci if (!err && sk->sk_err) 13988c2ecf20Sopenharmony_ci err = -sk->sk_err; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci release_sock(sk); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci BT_DBG("Sock shutdown complete err: %d", err); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci return err; 14058c2ecf20Sopenharmony_ci} 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_cistatic int l2cap_sock_release(struct socket *sock) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 14108c2ecf20Sopenharmony_ci int err; 14118c2ecf20Sopenharmony_ci struct l2cap_chan *chan; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci BT_DBG("sock %p, sk %p", sock, sk); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (!sk) 14168c2ecf20Sopenharmony_ci return 0; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci l2cap_sock_cleanup_listen(sk); 14198c2ecf20Sopenharmony_ci bt_sock_unlink(&l2cap_sk_list, sk); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci err = l2cap_sock_shutdown(sock, SHUT_RDWR); 14228c2ecf20Sopenharmony_ci chan = l2cap_pi(sk)->chan; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci l2cap_chan_hold(chan); 14258c2ecf20Sopenharmony_ci l2cap_chan_lock(chan); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci sock_orphan(sk); 14288c2ecf20Sopenharmony_ci l2cap_sock_kill(sk); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci l2cap_chan_unlock(chan); 14318c2ecf20Sopenharmony_ci l2cap_chan_put(chan); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci return err; 14348c2ecf20Sopenharmony_ci} 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_cistatic void l2cap_sock_cleanup_listen(struct sock *parent) 14378c2ecf20Sopenharmony_ci{ 14388c2ecf20Sopenharmony_ci struct sock *sk; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci BT_DBG("parent %p state %s", parent, 14418c2ecf20Sopenharmony_ci state_to_string(parent->sk_state)); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci /* Close not yet accepted channels */ 14448c2ecf20Sopenharmony_ci while ((sk = bt_accept_dequeue(parent, NULL))) { 14458c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci BT_DBG("child chan %p state %s", chan, 14488c2ecf20Sopenharmony_ci state_to_string(chan->state)); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci l2cap_chan_hold(chan); 14518c2ecf20Sopenharmony_ci l2cap_chan_lock(chan); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci __clear_chan_timer(chan); 14548c2ecf20Sopenharmony_ci l2cap_chan_close(chan, ECONNRESET); 14558c2ecf20Sopenharmony_ci l2cap_sock_kill(sk); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci l2cap_chan_unlock(chan); 14588c2ecf20Sopenharmony_ci l2cap_chan_put(chan); 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci} 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_cistatic struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan) 14638c2ecf20Sopenharmony_ci{ 14648c2ecf20Sopenharmony_ci struct sock *sk, *parent = chan->data; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci lock_sock(parent); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci /* Check for backlog size */ 14698c2ecf20Sopenharmony_ci if (sk_acceptq_is_full(parent)) { 14708c2ecf20Sopenharmony_ci BT_DBG("backlog full %d", parent->sk_ack_backlog); 14718c2ecf20Sopenharmony_ci release_sock(parent); 14728c2ecf20Sopenharmony_ci return NULL; 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, 14768c2ecf20Sopenharmony_ci GFP_ATOMIC, 0); 14778c2ecf20Sopenharmony_ci if (!sk) { 14788c2ecf20Sopenharmony_ci release_sock(parent); 14798c2ecf20Sopenharmony_ci return NULL; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci bt_sock_reclassify_lock(sk, BTPROTO_L2CAP); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci l2cap_sock_init(sk, parent); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci bt_accept_enqueue(parent, sk, false); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci release_sock(parent); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci return l2cap_pi(sk)->chan; 14918c2ecf20Sopenharmony_ci} 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_cistatic int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) 14948c2ecf20Sopenharmony_ci{ 14958c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 14968c2ecf20Sopenharmony_ci int err; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci lock_sock(sk); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci if (l2cap_pi(sk)->rx_busy_skb) { 15018c2ecf20Sopenharmony_ci err = -ENOMEM; 15028c2ecf20Sopenharmony_ci goto done; 15038c2ecf20Sopenharmony_ci } 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci if (chan->mode != L2CAP_MODE_ERTM && 15068c2ecf20Sopenharmony_ci chan->mode != L2CAP_MODE_STREAMING) { 15078c2ecf20Sopenharmony_ci /* Even if no filter is attached, we could potentially 15088c2ecf20Sopenharmony_ci * get errors from security modules, etc. 15098c2ecf20Sopenharmony_ci */ 15108c2ecf20Sopenharmony_ci err = sk_filter(sk, skb); 15118c2ecf20Sopenharmony_ci if (err) 15128c2ecf20Sopenharmony_ci goto done; 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci err = __sock_queue_rcv_skb(sk, skb); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci /* For ERTM, handle one skb that doesn't fit into the recv 15188c2ecf20Sopenharmony_ci * buffer. This is important to do because the data frames 15198c2ecf20Sopenharmony_ci * have already been acked, so the skb cannot be discarded. 15208c2ecf20Sopenharmony_ci * 15218c2ecf20Sopenharmony_ci * Notify the l2cap core that the buffer is full, so the 15228c2ecf20Sopenharmony_ci * LOCAL_BUSY state is entered and no more frames are 15238c2ecf20Sopenharmony_ci * acked and reassembled until there is buffer space 15248c2ecf20Sopenharmony_ci * available. 15258c2ecf20Sopenharmony_ci */ 15268c2ecf20Sopenharmony_ci if (err < 0 && chan->mode == L2CAP_MODE_ERTM) { 15278c2ecf20Sopenharmony_ci l2cap_pi(sk)->rx_busy_skb = skb; 15288c2ecf20Sopenharmony_ci l2cap_chan_busy(chan, 1); 15298c2ecf20Sopenharmony_ci err = 0; 15308c2ecf20Sopenharmony_ci } 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_cidone: 15338c2ecf20Sopenharmony_ci release_sock(sk); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci return err; 15368c2ecf20Sopenharmony_ci} 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_cistatic void l2cap_sock_close_cb(struct l2cap_chan *chan) 15398c2ecf20Sopenharmony_ci{ 15408c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci if (!sk) 15438c2ecf20Sopenharmony_ci return; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci l2cap_sock_kill(sk); 15468c2ecf20Sopenharmony_ci} 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_cistatic void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 15518c2ecf20Sopenharmony_ci struct sock *parent; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (!sk) 15548c2ecf20Sopenharmony_ci return; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci /* This callback can be called both for server (BT_LISTEN) 15598c2ecf20Sopenharmony_ci * sockets as well as "normal" ones. To avoid lockdep warnings 15608c2ecf20Sopenharmony_ci * with child socket locking (through l2cap_sock_cleanup_listen) 15618c2ecf20Sopenharmony_ci * we need separation into separate nesting levels. The simplest 15628c2ecf20Sopenharmony_ci * way to accomplish this is to inherit the nesting level used 15638c2ecf20Sopenharmony_ci * for the channel. 15648c2ecf20Sopenharmony_ci */ 15658c2ecf20Sopenharmony_ci lock_sock_nested(sk, atomic_read(&chan->nesting)); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci parent = bt_sk(sk)->parent; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci switch (chan->state) { 15708c2ecf20Sopenharmony_ci case BT_OPEN: 15718c2ecf20Sopenharmony_ci case BT_BOUND: 15728c2ecf20Sopenharmony_ci case BT_CLOSED: 15738c2ecf20Sopenharmony_ci break; 15748c2ecf20Sopenharmony_ci case BT_LISTEN: 15758c2ecf20Sopenharmony_ci l2cap_sock_cleanup_listen(sk); 15768c2ecf20Sopenharmony_ci sk->sk_state = BT_CLOSED; 15778c2ecf20Sopenharmony_ci chan->state = BT_CLOSED; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci break; 15808c2ecf20Sopenharmony_ci default: 15818c2ecf20Sopenharmony_ci sk->sk_state = BT_CLOSED; 15828c2ecf20Sopenharmony_ci chan->state = BT_CLOSED; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci sk->sk_err = err; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci if (parent) { 15878c2ecf20Sopenharmony_ci bt_accept_unlink(sk); 15888c2ecf20Sopenharmony_ci parent->sk_data_ready(parent); 15898c2ecf20Sopenharmony_ci } else { 15908c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci break; 15948c2ecf20Sopenharmony_ci } 15958c2ecf20Sopenharmony_ci release_sock(sk); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci /* Only zap after cleanup to avoid use after free race */ 15988c2ecf20Sopenharmony_ci sock_set_flag(sk, SOCK_ZAPPED); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci} 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_cistatic void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state, 16038c2ecf20Sopenharmony_ci int err) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci sk->sk_state = state; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci if (err) 16108c2ecf20Sopenharmony_ci sk->sk_err = err; 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_cistatic struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, 16148c2ecf20Sopenharmony_ci unsigned long hdr_len, 16158c2ecf20Sopenharmony_ci unsigned long len, int nb) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 16188c2ecf20Sopenharmony_ci struct sk_buff *skb; 16198c2ecf20Sopenharmony_ci int err; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci l2cap_chan_unlock(chan); 16228c2ecf20Sopenharmony_ci skb = bt_skb_send_alloc(sk, hdr_len + len, nb, &err); 16238c2ecf20Sopenharmony_ci l2cap_chan_lock(chan); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci if (!skb) 16268c2ecf20Sopenharmony_ci return ERR_PTR(err); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci /* Channel lock is released before requesting new skb and then 16298c2ecf20Sopenharmony_ci * reacquired thus we need to recheck channel state. 16308c2ecf20Sopenharmony_ci */ 16318c2ecf20Sopenharmony_ci if (chan->state != BT_CONNECTED) { 16328c2ecf20Sopenharmony_ci kfree_skb(skb); 16338c2ecf20Sopenharmony_ci return ERR_PTR(-ENOTCONN); 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci skb->priority = sk->sk_priority; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci bt_cb(skb)->l2cap.chan = chan; 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci return skb; 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic void l2cap_sock_ready_cb(struct l2cap_chan *chan) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 16468c2ecf20Sopenharmony_ci struct sock *parent; 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci lock_sock(sk); 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci parent = bt_sk(sk)->parent; 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci BT_DBG("sk %p, parent %p", sk, parent); 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci sk->sk_state = BT_CONNECTED; 16558c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (parent) 16588c2ecf20Sopenharmony_ci parent->sk_data_ready(parent); 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci release_sock(sk); 16618c2ecf20Sopenharmony_ci} 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_cistatic void l2cap_sock_defer_cb(struct l2cap_chan *chan) 16648c2ecf20Sopenharmony_ci{ 16658c2ecf20Sopenharmony_ci struct sock *parent, *sk = chan->data; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci lock_sock(sk); 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci parent = bt_sk(sk)->parent; 16708c2ecf20Sopenharmony_ci if (parent) 16718c2ecf20Sopenharmony_ci parent->sk_data_ready(parent); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci release_sock(sk); 16748c2ecf20Sopenharmony_ci} 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_cistatic void l2cap_sock_resume_cb(struct l2cap_chan *chan) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLAG_PENDING_SECURITY, &chan->flags)) { 16818c2ecf20Sopenharmony_ci sk->sk_state = BT_CONNECTED; 16828c2ecf20Sopenharmony_ci chan->state = BT_CONNECTED; 16838c2ecf20Sopenharmony_ci } 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); 16868c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 16878c2ecf20Sopenharmony_ci} 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_cistatic void l2cap_sock_set_shutdown_cb(struct l2cap_chan *chan) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci lock_sock(sk); 16948c2ecf20Sopenharmony_ci sk->sk_shutdown = SHUTDOWN_MASK; 16958c2ecf20Sopenharmony_ci release_sock(sk); 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_cistatic long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan) 16998c2ecf20Sopenharmony_ci{ 17008c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci return sk->sk_sndtimeo; 17038c2ecf20Sopenharmony_ci} 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_cistatic struct pid *l2cap_sock_get_peer_pid_cb(struct l2cap_chan *chan) 17068c2ecf20Sopenharmony_ci{ 17078c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci return sk->sk_peer_pid; 17108c2ecf20Sopenharmony_ci} 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_cistatic void l2cap_sock_suspend_cb(struct l2cap_chan *chan) 17138c2ecf20Sopenharmony_ci{ 17148c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); 17178c2ecf20Sopenharmony_ci sk->sk_state_change(sk); 17188c2ecf20Sopenharmony_ci} 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_cistatic int l2cap_sock_filter(struct l2cap_chan *chan, struct sk_buff *skb) 17218c2ecf20Sopenharmony_ci{ 17228c2ecf20Sopenharmony_ci struct sock *sk = chan->data; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci switch (chan->mode) { 17258c2ecf20Sopenharmony_ci case L2CAP_MODE_ERTM: 17268c2ecf20Sopenharmony_ci case L2CAP_MODE_STREAMING: 17278c2ecf20Sopenharmony_ci return sk_filter(sk, skb); 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci return 0; 17318c2ecf20Sopenharmony_ci} 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_cistatic const struct l2cap_ops l2cap_chan_ops = { 17348c2ecf20Sopenharmony_ci .name = "L2CAP Socket Interface", 17358c2ecf20Sopenharmony_ci .new_connection = l2cap_sock_new_connection_cb, 17368c2ecf20Sopenharmony_ci .recv = l2cap_sock_recv_cb, 17378c2ecf20Sopenharmony_ci .close = l2cap_sock_close_cb, 17388c2ecf20Sopenharmony_ci .teardown = l2cap_sock_teardown_cb, 17398c2ecf20Sopenharmony_ci .state_change = l2cap_sock_state_change_cb, 17408c2ecf20Sopenharmony_ci .ready = l2cap_sock_ready_cb, 17418c2ecf20Sopenharmony_ci .defer = l2cap_sock_defer_cb, 17428c2ecf20Sopenharmony_ci .resume = l2cap_sock_resume_cb, 17438c2ecf20Sopenharmony_ci .suspend = l2cap_sock_suspend_cb, 17448c2ecf20Sopenharmony_ci .set_shutdown = l2cap_sock_set_shutdown_cb, 17458c2ecf20Sopenharmony_ci .get_sndtimeo = l2cap_sock_get_sndtimeo_cb, 17468c2ecf20Sopenharmony_ci .get_peer_pid = l2cap_sock_get_peer_pid_cb, 17478c2ecf20Sopenharmony_ci .alloc_skb = l2cap_sock_alloc_skb_cb, 17488c2ecf20Sopenharmony_ci .filter = l2cap_sock_filter, 17498c2ecf20Sopenharmony_ci}; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_cistatic void l2cap_sock_destruct(struct sock *sk) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci BT_DBG("sk %p", sk); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci if (l2cap_pi(sk)->chan) { 17568c2ecf20Sopenharmony_ci l2cap_pi(sk)->chan->data = NULL; 17578c2ecf20Sopenharmony_ci l2cap_chan_put(l2cap_pi(sk)->chan); 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci if (l2cap_pi(sk)->rx_busy_skb) { 17618c2ecf20Sopenharmony_ci kfree_skb(l2cap_pi(sk)->rx_busy_skb); 17628c2ecf20Sopenharmony_ci l2cap_pi(sk)->rx_busy_skb = NULL; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 17668c2ecf20Sopenharmony_ci skb_queue_purge(&sk->sk_write_queue); 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_cistatic void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name, 17708c2ecf20Sopenharmony_ci int *msg_namelen) 17718c2ecf20Sopenharmony_ci{ 17728c2ecf20Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_l2 *, la, msg_name); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci memset(la, 0, sizeof(struct sockaddr_l2)); 17758c2ecf20Sopenharmony_ci la->l2_family = AF_BLUETOOTH; 17768c2ecf20Sopenharmony_ci la->l2_psm = bt_cb(skb)->l2cap.psm; 17778c2ecf20Sopenharmony_ci bacpy(&la->l2_bdaddr, &bt_cb(skb)->l2cap.bdaddr); 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci *msg_namelen = sizeof(struct sockaddr_l2); 17808c2ecf20Sopenharmony_ci} 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_cistatic void l2cap_sock_init(struct sock *sk, struct sock *parent) 17838c2ecf20Sopenharmony_ci{ 17848c2ecf20Sopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci BT_DBG("sk %p", sk); 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci if (parent) { 17898c2ecf20Sopenharmony_ci struct l2cap_chan *pchan = l2cap_pi(parent)->chan; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci sk->sk_type = parent->sk_type; 17928c2ecf20Sopenharmony_ci bt_sk(sk)->flags = bt_sk(parent)->flags; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci chan->chan_type = pchan->chan_type; 17958c2ecf20Sopenharmony_ci chan->imtu = pchan->imtu; 17968c2ecf20Sopenharmony_ci chan->omtu = pchan->omtu; 17978c2ecf20Sopenharmony_ci chan->conf_state = pchan->conf_state; 17988c2ecf20Sopenharmony_ci chan->mode = pchan->mode; 17998c2ecf20Sopenharmony_ci chan->fcs = pchan->fcs; 18008c2ecf20Sopenharmony_ci chan->max_tx = pchan->max_tx; 18018c2ecf20Sopenharmony_ci chan->tx_win = pchan->tx_win; 18028c2ecf20Sopenharmony_ci chan->tx_win_max = pchan->tx_win_max; 18038c2ecf20Sopenharmony_ci chan->sec_level = pchan->sec_level; 18048c2ecf20Sopenharmony_ci chan->flags = pchan->flags; 18058c2ecf20Sopenharmony_ci chan->tx_credits = pchan->tx_credits; 18068c2ecf20Sopenharmony_ci chan->rx_credits = pchan->rx_credits; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci if (chan->chan_type == L2CAP_CHAN_FIXED) { 18098c2ecf20Sopenharmony_ci chan->scid = pchan->scid; 18108c2ecf20Sopenharmony_ci chan->dcid = pchan->scid; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci security_sk_clone(parent, sk); 18148c2ecf20Sopenharmony_ci } else { 18158c2ecf20Sopenharmony_ci switch (sk->sk_type) { 18168c2ecf20Sopenharmony_ci case SOCK_RAW: 18178c2ecf20Sopenharmony_ci chan->chan_type = L2CAP_CHAN_RAW; 18188c2ecf20Sopenharmony_ci break; 18198c2ecf20Sopenharmony_ci case SOCK_DGRAM: 18208c2ecf20Sopenharmony_ci chan->chan_type = L2CAP_CHAN_CONN_LESS; 18218c2ecf20Sopenharmony_ci bt_sk(sk)->skb_msg_name = l2cap_skb_msg_name; 18228c2ecf20Sopenharmony_ci break; 18238c2ecf20Sopenharmony_ci case SOCK_SEQPACKET: 18248c2ecf20Sopenharmony_ci case SOCK_STREAM: 18258c2ecf20Sopenharmony_ci chan->chan_type = L2CAP_CHAN_CONN_ORIENTED; 18268c2ecf20Sopenharmony_ci break; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci chan->imtu = L2CAP_DEFAULT_MTU; 18308c2ecf20Sopenharmony_ci chan->omtu = 0; 18318c2ecf20Sopenharmony_ci if (!disable_ertm && sk->sk_type == SOCK_STREAM) { 18328c2ecf20Sopenharmony_ci chan->mode = L2CAP_MODE_ERTM; 18338c2ecf20Sopenharmony_ci set_bit(CONF_STATE2_DEVICE, &chan->conf_state); 18348c2ecf20Sopenharmony_ci } else { 18358c2ecf20Sopenharmony_ci chan->mode = L2CAP_MODE_BASIC; 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci l2cap_chan_set_defaults(chan); 18398c2ecf20Sopenharmony_ci } 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci /* Default config options */ 18428c2ecf20Sopenharmony_ci chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci chan->data = sk; 18458c2ecf20Sopenharmony_ci chan->ops = &l2cap_chan_ops; 18468c2ecf20Sopenharmony_ci} 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_cistatic struct proto l2cap_proto = { 18498c2ecf20Sopenharmony_ci .name = "L2CAP", 18508c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 18518c2ecf20Sopenharmony_ci .obj_size = sizeof(struct l2cap_pinfo) 18528c2ecf20Sopenharmony_ci}; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_cistatic struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, 18558c2ecf20Sopenharmony_ci int proto, gfp_t prio, int kern) 18568c2ecf20Sopenharmony_ci{ 18578c2ecf20Sopenharmony_ci struct sock *sk; 18588c2ecf20Sopenharmony_ci struct l2cap_chan *chan; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto, kern); 18618c2ecf20Sopenharmony_ci if (!sk) 18628c2ecf20Sopenharmony_ci return NULL; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci sock_init_data(sock, sk); 18658c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bt_sk(sk)->accept_q); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci sk->sk_destruct = l2cap_sock_destruct; 18688c2ecf20Sopenharmony_ci sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci sock_reset_flag(sk, SOCK_ZAPPED); 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci sk->sk_protocol = proto; 18738c2ecf20Sopenharmony_ci sk->sk_state = BT_OPEN; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci chan = l2cap_chan_create(); 18768c2ecf20Sopenharmony_ci if (!chan) { 18778c2ecf20Sopenharmony_ci sk_free(sk); 18788c2ecf20Sopenharmony_ci return NULL; 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci l2cap_chan_hold(chan); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci l2cap_pi(sk)->chan = chan; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci return sk; 18868c2ecf20Sopenharmony_ci} 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_cistatic int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, 18898c2ecf20Sopenharmony_ci int kern) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci struct sock *sk; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci BT_DBG("sock %p", sock); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci sock->state = SS_UNCONNECTED; 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM && 18988c2ecf20Sopenharmony_ci sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) 18998c2ecf20Sopenharmony_ci return -ESOCKTNOSUPPORT; 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) 19028c2ecf20Sopenharmony_ci return -EPERM; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci sock->ops = &l2cap_sock_ops; 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern); 19078c2ecf20Sopenharmony_ci if (!sk) 19088c2ecf20Sopenharmony_ci return -ENOMEM; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci l2cap_sock_init(sk, NULL); 19118c2ecf20Sopenharmony_ci bt_sock_link(&l2cap_sk_list, sk); 19128c2ecf20Sopenharmony_ci return 0; 19138c2ecf20Sopenharmony_ci} 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_cistatic const struct proto_ops l2cap_sock_ops = { 19168c2ecf20Sopenharmony_ci .family = PF_BLUETOOTH, 19178c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 19188c2ecf20Sopenharmony_ci .release = l2cap_sock_release, 19198c2ecf20Sopenharmony_ci .bind = l2cap_sock_bind, 19208c2ecf20Sopenharmony_ci .connect = l2cap_sock_connect, 19218c2ecf20Sopenharmony_ci .listen = l2cap_sock_listen, 19228c2ecf20Sopenharmony_ci .accept = l2cap_sock_accept, 19238c2ecf20Sopenharmony_ci .getname = l2cap_sock_getname, 19248c2ecf20Sopenharmony_ci .sendmsg = l2cap_sock_sendmsg, 19258c2ecf20Sopenharmony_ci .recvmsg = l2cap_sock_recvmsg, 19268c2ecf20Sopenharmony_ci .poll = bt_sock_poll, 19278c2ecf20Sopenharmony_ci .ioctl = bt_sock_ioctl, 19288c2ecf20Sopenharmony_ci .gettstamp = sock_gettstamp, 19298c2ecf20Sopenharmony_ci .mmap = sock_no_mmap, 19308c2ecf20Sopenharmony_ci .socketpair = sock_no_socketpair, 19318c2ecf20Sopenharmony_ci .shutdown = l2cap_sock_shutdown, 19328c2ecf20Sopenharmony_ci .setsockopt = l2cap_sock_setsockopt, 19338c2ecf20Sopenharmony_ci .getsockopt = l2cap_sock_getsockopt 19348c2ecf20Sopenharmony_ci}; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_cistatic const struct net_proto_family l2cap_sock_family_ops = { 19378c2ecf20Sopenharmony_ci .family = PF_BLUETOOTH, 19388c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 19398c2ecf20Sopenharmony_ci .create = l2cap_sock_create, 19408c2ecf20Sopenharmony_ci}; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ciint __init l2cap_init_sockets(void) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci int err; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct sockaddr_l2) > sizeof(struct sockaddr)); 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci err = proto_register(&l2cap_proto, 0); 19498c2ecf20Sopenharmony_ci if (err < 0) 19508c2ecf20Sopenharmony_ci return err; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops); 19538c2ecf20Sopenharmony_ci if (err < 0) { 19548c2ecf20Sopenharmony_ci BT_ERR("L2CAP socket registration failed"); 19558c2ecf20Sopenharmony_ci goto error; 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci err = bt_procfs_init(&init_net, "l2cap", &l2cap_sk_list, 19598c2ecf20Sopenharmony_ci NULL); 19608c2ecf20Sopenharmony_ci if (err < 0) { 19618c2ecf20Sopenharmony_ci BT_ERR("Failed to create L2CAP proc file"); 19628c2ecf20Sopenharmony_ci bt_sock_unregister(BTPROTO_L2CAP); 19638c2ecf20Sopenharmony_ci goto error; 19648c2ecf20Sopenharmony_ci } 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci BT_INFO("L2CAP socket layer initialized"); 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci return 0; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_cierror: 19718c2ecf20Sopenharmony_ci proto_unregister(&l2cap_proto); 19728c2ecf20Sopenharmony_ci return err; 19738c2ecf20Sopenharmony_ci} 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_civoid l2cap_cleanup_sockets(void) 19768c2ecf20Sopenharmony_ci{ 19778c2ecf20Sopenharmony_ci bt_procfs_cleanup(&init_net, "l2cap"); 19788c2ecf20Sopenharmony_ci bt_sock_unregister(BTPROTO_L2CAP); 19798c2ecf20Sopenharmony_ci proto_unregister(&l2cap_proto); 19808c2ecf20Sopenharmony_ci} 1981