13d0407baSopenharmony_ci/* 23d0407baSopenharmony_ci BlueZ - Bluetooth protocol stack for Linux 33d0407baSopenharmony_ci Copyright (C) 2000-2001 Qualcomm Incorporated 43d0407baSopenharmony_ci Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org> 53d0407baSopenharmony_ci Copyright (C) 2010 Google Inc. 63d0407baSopenharmony_ci Copyright (C) 2011 ProFUSION Embedded Systems 73d0407baSopenharmony_ci 83d0407baSopenharmony_ci Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> 93d0407baSopenharmony_ci 103d0407baSopenharmony_ci This program is free software; you can redistribute it and/or modify 113d0407baSopenharmony_ci it under the terms of the GNU General Public License version 2 as 123d0407baSopenharmony_ci published by the Free Software Foundation; 133d0407baSopenharmony_ci 143d0407baSopenharmony_ci THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 153d0407baSopenharmony_ci OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 163d0407baSopenharmony_ci FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 173d0407baSopenharmony_ci IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 183d0407baSopenharmony_ci CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 193d0407baSopenharmony_ci WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 203d0407baSopenharmony_ci ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 213d0407baSopenharmony_ci OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 223d0407baSopenharmony_ci 233d0407baSopenharmony_ci ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 243d0407baSopenharmony_ci COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 253d0407baSopenharmony_ci SOFTWARE IS DISCLAIMED. 263d0407baSopenharmony_ci*/ 273d0407baSopenharmony_ci 283d0407baSopenharmony_ci/* Bluetooth L2CAP sockets. */ 293d0407baSopenharmony_ci 303d0407baSopenharmony_ci#include <linux/module.h> 313d0407baSopenharmony_ci#include <linux/export.h> 323d0407baSopenharmony_ci#include <linux/sched/signal.h> 333d0407baSopenharmony_ci 343d0407baSopenharmony_ci#include <net/bluetooth/bluetooth.h> 353d0407baSopenharmony_ci#include <net/bluetooth/hci_core.h> 363d0407baSopenharmony_ci#include <net/bluetooth/l2cap.h> 373d0407baSopenharmony_ci 383d0407baSopenharmony_ci#include "smp.h" 393d0407baSopenharmony_ci 403d0407baSopenharmony_cistatic struct bt_sock_list l2cap_sk_list = {.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)}; 413d0407baSopenharmony_ci 423d0407baSopenharmony_cistatic const struct proto_ops l2cap_sock_ops; 433d0407baSopenharmony_cistatic void l2cap_sock_init(struct sock *sk, struct sock *parent); 443d0407baSopenharmony_cistatic struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio, int kern); 453d0407baSopenharmony_ci 463d0407baSopenharmony_cibool l2cap_is_socket(struct socket *sock) 473d0407baSopenharmony_ci{ 483d0407baSopenharmony_ci return sock && sock->ops == &l2cap_sock_ops; 493d0407baSopenharmony_ci} 503d0407baSopenharmony_ciEXPORT_SYMBOL(l2cap_is_socket); 513d0407baSopenharmony_ci 523d0407baSopenharmony_cistatic int l2cap_validate_bredr_psm(u16 psm) 533d0407baSopenharmony_ci{ 543d0407baSopenharmony_ci /* PSM must be odd and lsb of upper byte must be 0 */ 553d0407baSopenharmony_ci if ((psm & 0x0101) != 0x0001) { 563d0407baSopenharmony_ci return -EINVAL; 573d0407baSopenharmony_ci } 583d0407baSopenharmony_ci 593d0407baSopenharmony_ci /* Restrict usage of well-known PSMs */ 603d0407baSopenharmony_ci if (psm < L2CAP_PSM_DYN_START && !capable(CAP_NET_BIND_SERVICE)) { 613d0407baSopenharmony_ci return -EACCES; 623d0407baSopenharmony_ci } 633d0407baSopenharmony_ci 643d0407baSopenharmony_ci return 0; 653d0407baSopenharmony_ci} 663d0407baSopenharmony_ci 673d0407baSopenharmony_cistatic int l2cap_validate_le_psm(u16 psm) 683d0407baSopenharmony_ci{ 693d0407baSopenharmony_ci /* Valid LE_PSM ranges are defined only until 0x00ff */ 703d0407baSopenharmony_ci if (psm > L2CAP_PSM_LE_DYN_END) { 713d0407baSopenharmony_ci return -EINVAL; 723d0407baSopenharmony_ci } 733d0407baSopenharmony_ci 743d0407baSopenharmony_ci /* Restrict fixed, SIG assigned PSM values to CAP_NET_BIND_SERVICE */ 753d0407baSopenharmony_ci if (psm < L2CAP_PSM_LE_DYN_START && !capable(CAP_NET_BIND_SERVICE)) { 763d0407baSopenharmony_ci return -EACCES; 773d0407baSopenharmony_ci } 783d0407baSopenharmony_ci 793d0407baSopenharmony_ci return 0; 803d0407baSopenharmony_ci} 813d0407baSopenharmony_ci 823d0407baSopenharmony_cistatic int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) 833d0407baSopenharmony_ci{ 843d0407baSopenharmony_ci struct sock *sk = sock->sk; 853d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 863d0407baSopenharmony_ci struct sockaddr_l2 la; 873d0407baSopenharmony_ci int len, err = 0; 883d0407baSopenharmony_ci 893d0407baSopenharmony_ci BT_DBG("sk %p", sk); 903d0407baSopenharmony_ci 913d0407baSopenharmony_ci if (!addr || alen < offsetofend(struct sockaddr, sa_family) || addr->sa_family != AF_BLUETOOTH) { 923d0407baSopenharmony_ci return -EINVAL; 933d0407baSopenharmony_ci } 943d0407baSopenharmony_ci 953d0407baSopenharmony_ci memset(&la, 0, sizeof(la)); 963d0407baSopenharmony_ci len = min_t(unsigned int, sizeof(la), alen); 973d0407baSopenharmony_ci memcpy(&la, addr, len); 983d0407baSopenharmony_ci 993d0407baSopenharmony_ci if (la.l2_cid && la.l2_psm) { 1003d0407baSopenharmony_ci return -EINVAL; 1013d0407baSopenharmony_ci } 1023d0407baSopenharmony_ci 1033d0407baSopenharmony_ci if (!bdaddr_type_is_valid(la.l2_bdaddr_type)) { 1043d0407baSopenharmony_ci return -EINVAL; 1053d0407baSopenharmony_ci } 1063d0407baSopenharmony_ci 1073d0407baSopenharmony_ci if (bdaddr_type_is_le(la.l2_bdaddr_type)) { 1083d0407baSopenharmony_ci /* We only allow ATT user space socket */ 1093d0407baSopenharmony_ci if (la.l2_cid && la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) { 1103d0407baSopenharmony_ci return -EINVAL; 1113d0407baSopenharmony_ci } 1123d0407baSopenharmony_ci } 1133d0407baSopenharmony_ci 1143d0407baSopenharmony_ci lock_sock(sk); 1153d0407baSopenharmony_ci 1163d0407baSopenharmony_ci if (sk->sk_state != BT_OPEN) { 1173d0407baSopenharmony_ci err = -EBADFD; 1183d0407baSopenharmony_ci goto done; 1193d0407baSopenharmony_ci } 1203d0407baSopenharmony_ci 1213d0407baSopenharmony_ci if (la.l2_psm) { 1223d0407baSopenharmony_ci __u16 psm = __le16_to_cpu(la.l2_psm); 1233d0407baSopenharmony_ci 1243d0407baSopenharmony_ci if (la.l2_bdaddr_type == BDADDR_BREDR) { 1253d0407baSopenharmony_ci err = l2cap_validate_bredr_psm(psm); 1263d0407baSopenharmony_ci } else { 1273d0407baSopenharmony_ci err = l2cap_validate_le_psm(psm); 1283d0407baSopenharmony_ci } 1293d0407baSopenharmony_ci 1303d0407baSopenharmony_ci if (err) { 1313d0407baSopenharmony_ci goto done; 1323d0407baSopenharmony_ci } 1333d0407baSopenharmony_ci } 1343d0407baSopenharmony_ci 1353d0407baSopenharmony_ci bacpy(&chan->src, &la.l2_bdaddr); 1363d0407baSopenharmony_ci chan->src_type = la.l2_bdaddr_type; 1373d0407baSopenharmony_ci 1383d0407baSopenharmony_ci if (la.l2_cid) { 1393d0407baSopenharmony_ci err = l2cap_add_scid(chan, __le16_to_cpu(la.l2_cid)); 1403d0407baSopenharmony_ci } else { 1413d0407baSopenharmony_ci err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm); 1423d0407baSopenharmony_ci } 1433d0407baSopenharmony_ci 1443d0407baSopenharmony_ci if (err < 0) { 1453d0407baSopenharmony_ci goto done; 1463d0407baSopenharmony_ci } 1473d0407baSopenharmony_ci 1483d0407baSopenharmony_ci switch (chan->chan_type) { 1493d0407baSopenharmony_ci case L2CAP_CHAN_CONN_LESS: 1503d0407baSopenharmony_ci if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_3DSP) { 1513d0407baSopenharmony_ci chan->sec_level = BT_SECURITY_SDP; 1523d0407baSopenharmony_ci } 1533d0407baSopenharmony_ci break; 1543d0407baSopenharmony_ci case L2CAP_CHAN_CONN_ORIENTED: 1553d0407baSopenharmony_ci if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP || __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM) { 1563d0407baSopenharmony_ci chan->sec_level = BT_SECURITY_SDP; 1573d0407baSopenharmony_ci } 1583d0407baSopenharmony_ci break; 1593d0407baSopenharmony_ci case L2CAP_CHAN_RAW: 1603d0407baSopenharmony_ci chan->sec_level = BT_SECURITY_SDP; 1613d0407baSopenharmony_ci break; 1623d0407baSopenharmony_ci case L2CAP_CHAN_FIXED: 1633d0407baSopenharmony_ci /* Fixed channels default to the L2CAP core not holding a 1643d0407baSopenharmony_ci * hci_conn reference for them. For fixed channels mapping to 1653d0407baSopenharmony_ci * L2CAP sockets we do want to hold a reference so set the 1663d0407baSopenharmony_ci * appropriate flag to request it. 1673d0407baSopenharmony_ci */ 1683d0407baSopenharmony_ci set_bit(FLAG_HOLD_HCI_CONN, &chan->flags); 1693d0407baSopenharmony_ci break; 1703d0407baSopenharmony_ci } 1713d0407baSopenharmony_ci 1723d0407baSopenharmony_ci if (chan->psm && bdaddr_type_is_le(chan->src_type) && 1733d0407baSopenharmony_ci chan->mode != L2CAP_MODE_EXT_FLOWCTL) { 1743d0407baSopenharmony_ci chan->mode = L2CAP_MODE_LE_FLOWCTL; 1753d0407baSopenharmony_ci } 1763d0407baSopenharmony_ci 1773d0407baSopenharmony_ci chan->state = BT_BOUND; 1783d0407baSopenharmony_ci sk->sk_state = BT_BOUND; 1793d0407baSopenharmony_ci 1803d0407baSopenharmony_cidone: 1813d0407baSopenharmony_ci release_sock(sk); 1823d0407baSopenharmony_ci return err; 1833d0407baSopenharmony_ci} 1843d0407baSopenharmony_ci 1853d0407baSopenharmony_cistatic void l2cap_sock_init_pid(struct sock *sk) 1863d0407baSopenharmony_ci{ 1873d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 1883d0407baSopenharmony_ci if (chan->mode != L2CAP_MODE_EXT_FLOWCTL) 1893d0407baSopenharmony_ci return; 1903d0407baSopenharmony_ci spin_lock(&sk->sk_peer_lock); 1913d0407baSopenharmony_ci sk->sk_peer_pid = get_pid(task_tgid(current)); 1923d0407baSopenharmony_ci spin_unlock(&sk->sk_peer_lock); 1933d0407baSopenharmony_ci} 1943d0407baSopenharmony_ci 1953d0407baSopenharmony_cistatic int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) 1963d0407baSopenharmony_ci{ 1973d0407baSopenharmony_ci struct sock *sk = sock->sk; 1983d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 1993d0407baSopenharmony_ci struct sockaddr_l2 la; 2003d0407baSopenharmony_ci int len, err = 0; 2013d0407baSopenharmony_ci bool zapped; 2023d0407baSopenharmony_ci 2033d0407baSopenharmony_ci BT_DBG("sk %p", sk); 2043d0407baSopenharmony_ci 2053d0407baSopenharmony_ci lock_sock(sk); 2063d0407baSopenharmony_ci zapped = sock_flag(sk, SOCK_ZAPPED); 2073d0407baSopenharmony_ci release_sock(sk); 2083d0407baSopenharmony_ci 2093d0407baSopenharmony_ci if (zapped) { 2103d0407baSopenharmony_ci return -EINVAL; 2113d0407baSopenharmony_ci } 2123d0407baSopenharmony_ci 2133d0407baSopenharmony_ci if (!addr || alen < offsetofend(struct sockaddr, sa_family) || addr->sa_family != AF_BLUETOOTH) { 2143d0407baSopenharmony_ci return -EINVAL; 2153d0407baSopenharmony_ci } 2163d0407baSopenharmony_ci 2173d0407baSopenharmony_ci memset(&la, 0, sizeof(la)); 2183d0407baSopenharmony_ci len = min_t(unsigned int, sizeof(la), alen); 2193d0407baSopenharmony_ci memcpy(&la, addr, len); 2203d0407baSopenharmony_ci 2213d0407baSopenharmony_ci if (la.l2_cid && la.l2_psm) { 2223d0407baSopenharmony_ci return -EINVAL; 2233d0407baSopenharmony_ci } 2243d0407baSopenharmony_ci 2253d0407baSopenharmony_ci if (!bdaddr_type_is_valid(la.l2_bdaddr_type)) { 2263d0407baSopenharmony_ci return -EINVAL; 2273d0407baSopenharmony_ci } 2283d0407baSopenharmony_ci 2293d0407baSopenharmony_ci /* Check that the socket wasn't bound to something that 2303d0407baSopenharmony_ci * conflicts with the address given to connect(). If chan->src 2313d0407baSopenharmony_ci * is BDADDR_ANY it means bind() was never used, in which case 2323d0407baSopenharmony_ci * chan->src_type and la.l2_bdaddr_type do not need to match. 2333d0407baSopenharmony_ci */ 2343d0407baSopenharmony_ci if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) && bdaddr_type_is_le(la.l2_bdaddr_type)) { 2353d0407baSopenharmony_ci /* Old user space versions will try to incorrectly bind 2363d0407baSopenharmony_ci * the ATT socket using BDADDR_BREDR. We need to accept 2373d0407baSopenharmony_ci * this and fix up the source address type only when 2383d0407baSopenharmony_ci * both the source CID and destination CID indicate 2393d0407baSopenharmony_ci * ATT. Anything else is an invalid combination. 2403d0407baSopenharmony_ci */ 2413d0407baSopenharmony_ci if (chan->scid != L2CAP_CID_ATT || la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) { 2423d0407baSopenharmony_ci return -EINVAL; 2433d0407baSopenharmony_ci } 2443d0407baSopenharmony_ci 2453d0407baSopenharmony_ci /* We don't have the hdev available here to make a 2463d0407baSopenharmony_ci * better decision on random vs public, but since all 2473d0407baSopenharmony_ci * user space versions that exhibit this issue anyway do 2483d0407baSopenharmony_ci * not support random local addresses assuming public 2493d0407baSopenharmony_ci * here is good enough. 2503d0407baSopenharmony_ci */ 2513d0407baSopenharmony_ci chan->src_type = BDADDR_LE_PUBLIC; 2523d0407baSopenharmony_ci } 2533d0407baSopenharmony_ci 2543d0407baSopenharmony_ci if (chan->src_type != BDADDR_BREDR && la.l2_bdaddr_type == BDADDR_BREDR) { 2553d0407baSopenharmony_ci return -EINVAL; 2563d0407baSopenharmony_ci } 2573d0407baSopenharmony_ci 2583d0407baSopenharmony_ci if (bdaddr_type_is_le(la.l2_bdaddr_type)) { 2593d0407baSopenharmony_ci /* We only allow ATT user space socket */ 2603d0407baSopenharmony_ci if (la.l2_cid && la.l2_cid != cpu_to_le16(L2CAP_CID_ATT)) { 2613d0407baSopenharmony_ci return -EINVAL; 2623d0407baSopenharmony_ci } 2633d0407baSopenharmony_ci } 2643d0407baSopenharmony_ci 2653d0407baSopenharmony_ci if (chan->psm && bdaddr_type_is_le(chan->src_type) && 2663d0407baSopenharmony_ci chan->mode != L2CAP_MODE_EXT_FLOWCTL) { 2673d0407baSopenharmony_ci chan->mode = L2CAP_MODE_LE_FLOWCTL; 2683d0407baSopenharmony_ci } 2693d0407baSopenharmony_ci 2703d0407baSopenharmony_ci l2cap_sock_init_pid(sk); 2713d0407baSopenharmony_ci 2723d0407baSopenharmony_ci err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), &la.l2_bdaddr, la.l2_bdaddr_type); 2733d0407baSopenharmony_ci if (err) { 2743d0407baSopenharmony_ci return err; 2753d0407baSopenharmony_ci } 2763d0407baSopenharmony_ci 2773d0407baSopenharmony_ci lock_sock(sk); 2783d0407baSopenharmony_ci 2793d0407baSopenharmony_ci err = bt_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); 2803d0407baSopenharmony_ci 2813d0407baSopenharmony_ci release_sock(sk); 2823d0407baSopenharmony_ci 2833d0407baSopenharmony_ci return err; 2843d0407baSopenharmony_ci} 2853d0407baSopenharmony_ci 2863d0407baSopenharmony_cistatic int l2cap_sock_listen(struct socket *sock, int backlog) 2873d0407baSopenharmony_ci{ 2883d0407baSopenharmony_ci struct sock *sk = sock->sk; 2893d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 2903d0407baSopenharmony_ci int err = 0; 2913d0407baSopenharmony_ci 2923d0407baSopenharmony_ci BT_DBG("sk %p backlog %d", sk, backlog); 2933d0407baSopenharmony_ci 2943d0407baSopenharmony_ci lock_sock(sk); 2953d0407baSopenharmony_ci 2963d0407baSopenharmony_ci if (sk->sk_state != BT_BOUND) { 2973d0407baSopenharmony_ci err = -EBADFD; 2983d0407baSopenharmony_ci goto done; 2993d0407baSopenharmony_ci } 3003d0407baSopenharmony_ci 3013d0407baSopenharmony_ci if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) { 3023d0407baSopenharmony_ci err = -EINVAL; 3033d0407baSopenharmony_ci goto done; 3043d0407baSopenharmony_ci } 3053d0407baSopenharmony_ci 3063d0407baSopenharmony_ci switch (chan->mode) { 3073d0407baSopenharmony_ci case L2CAP_MODE_BASIC: 3083d0407baSopenharmony_ci case L2CAP_MODE_LE_FLOWCTL: 3093d0407baSopenharmony_ci break; 3103d0407baSopenharmony_ci case L2CAP_MODE_EXT_FLOWCTL: 3113d0407baSopenharmony_ci if (!enable_ecred) { 3123d0407baSopenharmony_ci err = -EOPNOTSUPP; 3133d0407baSopenharmony_ci goto done; 3143d0407baSopenharmony_ci } 3153d0407baSopenharmony_ci break; 3163d0407baSopenharmony_ci case L2CAP_MODE_ERTM: 3173d0407baSopenharmony_ci case L2CAP_MODE_STREAMING: 3183d0407baSopenharmony_ci if (!disable_ertm) { 3193d0407baSopenharmony_ci break; 3203d0407baSopenharmony_ci } 3213d0407baSopenharmony_ci fallthrough; 3223d0407baSopenharmony_ci default: 3233d0407baSopenharmony_ci err = -EOPNOTSUPP; 3243d0407baSopenharmony_ci goto done; 3253d0407baSopenharmony_ci } 3263d0407baSopenharmony_ci 3273d0407baSopenharmony_ci l2cap_sock_init_pid(sk); 3283d0407baSopenharmony_ci sk->sk_max_ack_backlog = backlog; 3293d0407baSopenharmony_ci sk->sk_ack_backlog = 0; 3303d0407baSopenharmony_ci 3313d0407baSopenharmony_ci /* Listening channels need to use nested locking in order not to 3323d0407baSopenharmony_ci * cause lockdep warnings when the created child channels end up 3333d0407baSopenharmony_ci * being locked in the same thread as the parent channel. 3343d0407baSopenharmony_ci */ 3353d0407baSopenharmony_ci atomic_set(&chan->nesting, L2CAP_NESTING_PARENT); 3363d0407baSopenharmony_ci 3373d0407baSopenharmony_ci chan->state = BT_LISTEN; 3383d0407baSopenharmony_ci sk->sk_state = BT_LISTEN; 3393d0407baSopenharmony_ci 3403d0407baSopenharmony_cidone: 3413d0407baSopenharmony_ci release_sock(sk); 3423d0407baSopenharmony_ci return err; 3433d0407baSopenharmony_ci} 3443d0407baSopenharmony_ci 3453d0407baSopenharmony_cistatic int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags, bool kern) 3463d0407baSopenharmony_ci{ 3473d0407baSopenharmony_ci DEFINE_WAIT_FUNC(wait, woken_wake_function); 3483d0407baSopenharmony_ci struct sock *sk = sock->sk, *nsk; 3493d0407baSopenharmony_ci long timeo; 3503d0407baSopenharmony_ci int err = 0; 3513d0407baSopenharmony_ci 3523d0407baSopenharmony_ci lock_sock_nested(sk, L2CAP_NESTING_PARENT); 3533d0407baSopenharmony_ci 3543d0407baSopenharmony_ci timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); 3553d0407baSopenharmony_ci 3563d0407baSopenharmony_ci BT_DBG("sk %p timeo %ld", sk, timeo); 3573d0407baSopenharmony_ci 3583d0407baSopenharmony_ci /* Wait for an incoming connection. (wake-one). */ 3593d0407baSopenharmony_ci add_wait_queue_exclusive(sk_sleep(sk), &wait); 3603d0407baSopenharmony_ci while (1) { 3613d0407baSopenharmony_ci if (sk->sk_state != BT_LISTEN) { 3623d0407baSopenharmony_ci err = -EBADFD; 3633d0407baSopenharmony_ci break; 3643d0407baSopenharmony_ci } 3653d0407baSopenharmony_ci 3663d0407baSopenharmony_ci nsk = bt_accept_dequeue(sk, newsock); 3673d0407baSopenharmony_ci if (nsk) { 3683d0407baSopenharmony_ci break; 3693d0407baSopenharmony_ci } 3703d0407baSopenharmony_ci 3713d0407baSopenharmony_ci if (!timeo) { 3723d0407baSopenharmony_ci err = -EAGAIN; 3733d0407baSopenharmony_ci break; 3743d0407baSopenharmony_ci } 3753d0407baSopenharmony_ci 3763d0407baSopenharmony_ci if (signal_pending(current)) { 3773d0407baSopenharmony_ci err = sock_intr_errno(timeo); 3783d0407baSopenharmony_ci break; 3793d0407baSopenharmony_ci } 3803d0407baSopenharmony_ci 3813d0407baSopenharmony_ci release_sock(sk); 3823d0407baSopenharmony_ci 3833d0407baSopenharmony_ci timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); 3843d0407baSopenharmony_ci 3853d0407baSopenharmony_ci lock_sock_nested(sk, L2CAP_NESTING_PARENT); 3863d0407baSopenharmony_ci } 3873d0407baSopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 3883d0407baSopenharmony_ci 3893d0407baSopenharmony_ci if (err) { 3903d0407baSopenharmony_ci goto done; 3913d0407baSopenharmony_ci } 3923d0407baSopenharmony_ci 3933d0407baSopenharmony_ci newsock->state = SS_CONNECTED; 3943d0407baSopenharmony_ci 3953d0407baSopenharmony_ci BT_DBG("new socket %p", nsk); 3963d0407baSopenharmony_ci 3973d0407baSopenharmony_cidone: 3983d0407baSopenharmony_ci release_sock(sk); 3993d0407baSopenharmony_ci return err; 4003d0407baSopenharmony_ci} 4013d0407baSopenharmony_ci 4023d0407baSopenharmony_cistatic int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int peer) 4033d0407baSopenharmony_ci{ 4043d0407baSopenharmony_ci struct sockaddr_l2 *la = (struct sockaddr_l2 *)addr; 4053d0407baSopenharmony_ci struct sock *sk = sock->sk; 4063d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 4073d0407baSopenharmony_ci 4083d0407baSopenharmony_ci BT_DBG("sock %p, sk %p", sock, sk); 4093d0407baSopenharmony_ci 4103d0407baSopenharmony_ci if (peer && sk->sk_state != BT_CONNECTED && sk->sk_state != BT_CONNECT && sk->sk_state != BT_CONNECT2 && 4113d0407baSopenharmony_ci sk->sk_state != BT_CONFIG) { 4123d0407baSopenharmony_ci return -ENOTCONN; 4133d0407baSopenharmony_ci } 4143d0407baSopenharmony_ci 4153d0407baSopenharmony_ci memset(la, 0, sizeof(struct sockaddr_l2)); 4163d0407baSopenharmony_ci addr->sa_family = AF_BLUETOOTH; 4173d0407baSopenharmony_ci 4183d0407baSopenharmony_ci la->l2_psm = chan->psm; 4193d0407baSopenharmony_ci 4203d0407baSopenharmony_ci if (peer) { 4213d0407baSopenharmony_ci bacpy(&la->l2_bdaddr, &chan->dst); 4223d0407baSopenharmony_ci la->l2_cid = cpu_to_le16(chan->dcid); 4233d0407baSopenharmony_ci la->l2_bdaddr_type = chan->dst_type; 4243d0407baSopenharmony_ci } else { 4253d0407baSopenharmony_ci bacpy(&la->l2_bdaddr, &chan->src); 4263d0407baSopenharmony_ci la->l2_cid = cpu_to_le16(chan->scid); 4273d0407baSopenharmony_ci la->l2_bdaddr_type = chan->src_type; 4283d0407baSopenharmony_ci } 4293d0407baSopenharmony_ci 4303d0407baSopenharmony_ci return sizeof(struct sockaddr_l2); 4313d0407baSopenharmony_ci} 4323d0407baSopenharmony_ci 4333d0407baSopenharmony_cistatic int l2cap_get_mode(struct l2cap_chan *chan) 4343d0407baSopenharmony_ci{ 4353d0407baSopenharmony_ci switch (chan->mode) { 4363d0407baSopenharmony_ci case L2CAP_MODE_BASIC: 4373d0407baSopenharmony_ci return BT_MODE_BASIC; 4383d0407baSopenharmony_ci case L2CAP_MODE_ERTM: 4393d0407baSopenharmony_ci return BT_MODE_ERTM; 4403d0407baSopenharmony_ci case L2CAP_MODE_STREAMING: 4413d0407baSopenharmony_ci return BT_MODE_STREAMING; 4423d0407baSopenharmony_ci case L2CAP_MODE_LE_FLOWCTL: 4433d0407baSopenharmony_ci return BT_MODE_LE_FLOWCTL; 4443d0407baSopenharmony_ci case L2CAP_MODE_EXT_FLOWCTL: 4453d0407baSopenharmony_ci return BT_MODE_EXT_FLOWCTL; 4463d0407baSopenharmony_ci } 4473d0407baSopenharmony_ci 4483d0407baSopenharmony_ci return -EINVAL; 4493d0407baSopenharmony_ci} 4503d0407baSopenharmony_ci 4513d0407baSopenharmony_cistatic int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen) 4523d0407baSopenharmony_ci{ 4533d0407baSopenharmony_ci struct sock *sk = sock->sk; 4543d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 4553d0407baSopenharmony_ci struct l2cap_options opts; 4563d0407baSopenharmony_ci struct l2cap_conninfo cinfo; 4573d0407baSopenharmony_ci int len, err = 0; 4583d0407baSopenharmony_ci u32 opt; 4593d0407baSopenharmony_ci 4603d0407baSopenharmony_ci BT_DBG("sk %p", sk); 4613d0407baSopenharmony_ci 4623d0407baSopenharmony_ci if (get_user(len, optlen)) { 4633d0407baSopenharmony_ci return -EFAULT; 4643d0407baSopenharmony_ci } 4653d0407baSopenharmony_ci 4663d0407baSopenharmony_ci lock_sock(sk); 4673d0407baSopenharmony_ci 4683d0407baSopenharmony_ci switch (optname) { 4693d0407baSopenharmony_ci case L2CAP_OPTIONS: 4703d0407baSopenharmony_ci /* LE sockets should use BT_SNDMTU/BT_RCVMTU, but since 4713d0407baSopenharmony_ci * legacy ATT code depends on getsockopt for 4723d0407baSopenharmony_ci * L2CAP_OPTIONS we need to let this pass. 4733d0407baSopenharmony_ci */ 4743d0407baSopenharmony_ci if (bdaddr_type_is_le(chan->src_type) && chan->scid != L2CAP_CID_ATT) { 4753d0407baSopenharmony_ci err = -EINVAL; 4763d0407baSopenharmony_ci break; 4773d0407baSopenharmony_ci } 4783d0407baSopenharmony_ci 4793d0407baSopenharmony_ci /* Only BR/EDR modes are supported here */ 4803d0407baSopenharmony_ci switch (chan->mode) { 4813d0407baSopenharmony_ci case L2CAP_MODE_BASIC: 4823d0407baSopenharmony_ci case L2CAP_MODE_ERTM: 4833d0407baSopenharmony_ci case L2CAP_MODE_STREAMING: 4843d0407baSopenharmony_ci break; 4853d0407baSopenharmony_ci default: 4863d0407baSopenharmony_ci err = -EINVAL; 4873d0407baSopenharmony_ci break; 4883d0407baSopenharmony_ci } 4893d0407baSopenharmony_ci 4903d0407baSopenharmony_ci if (err < 0) { 4913d0407baSopenharmony_ci break; 4923d0407baSopenharmony_ci } 4933d0407baSopenharmony_ci 4943d0407baSopenharmony_ci memset(&opts, 0, sizeof(opts)); 4953d0407baSopenharmony_ci opts.imtu = chan->imtu; 4963d0407baSopenharmony_ci opts.omtu = chan->omtu; 4973d0407baSopenharmony_ci opts.flush_to = chan->flush_to; 4983d0407baSopenharmony_ci opts.mode = chan->mode; 4993d0407baSopenharmony_ci opts.fcs = chan->fcs; 5003d0407baSopenharmony_ci opts.max_tx = chan->max_tx; 5013d0407baSopenharmony_ci opts.txwin_size = chan->tx_win; 5023d0407baSopenharmony_ci 5033d0407baSopenharmony_ci BT_DBG("mode 0x%2.2x", chan->mode); 5043d0407baSopenharmony_ci 5053d0407baSopenharmony_ci len = min_t(unsigned int, len, sizeof(opts)); 5063d0407baSopenharmony_ci if (copy_to_user(optval, (char *)&opts, len)) { 5073d0407baSopenharmony_ci err = -EFAULT; 5083d0407baSopenharmony_ci } 5093d0407baSopenharmony_ci 5103d0407baSopenharmony_ci break; 5113d0407baSopenharmony_ci 5123d0407baSopenharmony_ci case L2CAP_LM: 5133d0407baSopenharmony_ci switch (chan->sec_level) { 5143d0407baSopenharmony_ci case BT_SECURITY_LOW: 5153d0407baSopenharmony_ci opt = L2CAP_LM_AUTH; 5163d0407baSopenharmony_ci break; 5173d0407baSopenharmony_ci case BT_SECURITY_MEDIUM: 5183d0407baSopenharmony_ci opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT; 5193d0407baSopenharmony_ci break; 5203d0407baSopenharmony_ci case BT_SECURITY_HIGH: 5213d0407baSopenharmony_ci opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE; 5223d0407baSopenharmony_ci break; 5233d0407baSopenharmony_ci case BT_SECURITY_FIPS: 5243d0407baSopenharmony_ci opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE | L2CAP_LM_FIPS; 5253d0407baSopenharmony_ci break; 5263d0407baSopenharmony_ci default: 5273d0407baSopenharmony_ci opt = 0; 5283d0407baSopenharmony_ci break; 5293d0407baSopenharmony_ci } 5303d0407baSopenharmony_ci 5313d0407baSopenharmony_ci if (test_bit(FLAG_ROLE_SWITCH, &chan->flags)) { 5323d0407baSopenharmony_ci opt |= L2CAP_LM_MASTER; 5333d0407baSopenharmony_ci } 5343d0407baSopenharmony_ci 5353d0407baSopenharmony_ci if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) { 5363d0407baSopenharmony_ci opt |= L2CAP_LM_RELIABLE; 5373d0407baSopenharmony_ci } 5383d0407baSopenharmony_ci 5393d0407baSopenharmony_ci if (put_user(opt, (u32 __user *)optval)) { 5403d0407baSopenharmony_ci err = -EFAULT; 5413d0407baSopenharmony_ci } 5423d0407baSopenharmony_ci 5433d0407baSopenharmony_ci break; 5443d0407baSopenharmony_ci 5453d0407baSopenharmony_ci case L2CAP_CONNINFO: 5463d0407baSopenharmony_ci if (sk->sk_state != BT_CONNECTED && 5473d0407baSopenharmony_ci !(sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) { 5483d0407baSopenharmony_ci err = -ENOTCONN; 5493d0407baSopenharmony_ci break; 5503d0407baSopenharmony_ci } 5513d0407baSopenharmony_ci 5523d0407baSopenharmony_ci memset(&cinfo, 0, sizeof(cinfo)); 5533d0407baSopenharmony_ci cinfo.hci_handle = chan->conn->hcon->handle; 5543d0407baSopenharmony_ci memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3); 5553d0407baSopenharmony_ci 5563d0407baSopenharmony_ci len = min_t(unsigned int, len, sizeof(cinfo)); 5573d0407baSopenharmony_ci if (copy_to_user(optval, (char *)&cinfo, len)) { 5583d0407baSopenharmony_ci err = -EFAULT; 5593d0407baSopenharmony_ci } 5603d0407baSopenharmony_ci 5613d0407baSopenharmony_ci break; 5623d0407baSopenharmony_ci 5633d0407baSopenharmony_ci default: 5643d0407baSopenharmony_ci err = -ENOPROTOOPT; 5653d0407baSopenharmony_ci break; 5663d0407baSopenharmony_ci } 5673d0407baSopenharmony_ci 5683d0407baSopenharmony_ci release_sock(sk); 5693d0407baSopenharmony_ci return err; 5703d0407baSopenharmony_ci} 5713d0407baSopenharmony_ci 5723d0407baSopenharmony_cistatic int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) 5733d0407baSopenharmony_ci{ 5743d0407baSopenharmony_ci struct sock *sk = sock->sk; 5753d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 5763d0407baSopenharmony_ci struct bt_security sec; 5773d0407baSopenharmony_ci struct bt_power pwr; 5783d0407baSopenharmony_ci u32 phys; 5793d0407baSopenharmony_ci int len, mode, err = 0; 5803d0407baSopenharmony_ci 5813d0407baSopenharmony_ci BT_DBG("sk %p", sk); 5823d0407baSopenharmony_ci 5833d0407baSopenharmony_ci if (level == SOL_L2CAP) { 5843d0407baSopenharmony_ci return l2cap_sock_getsockopt_old(sock, optname, optval, optlen); 5853d0407baSopenharmony_ci } 5863d0407baSopenharmony_ci 5873d0407baSopenharmony_ci if (level != SOL_BLUETOOTH) { 5883d0407baSopenharmony_ci return -ENOPROTOOPT; 5893d0407baSopenharmony_ci } 5903d0407baSopenharmony_ci 5913d0407baSopenharmony_ci if (get_user(len, optlen)) { 5923d0407baSopenharmony_ci return -EFAULT; 5933d0407baSopenharmony_ci } 5943d0407baSopenharmony_ci 5953d0407baSopenharmony_ci lock_sock(sk); 5963d0407baSopenharmony_ci 5973d0407baSopenharmony_ci switch (optname) { 5983d0407baSopenharmony_ci case BT_SECURITY: 5993d0407baSopenharmony_ci if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED && chan->chan_type != L2CAP_CHAN_FIXED && 6003d0407baSopenharmony_ci chan->chan_type != L2CAP_CHAN_RAW) { 6013d0407baSopenharmony_ci err = -EINVAL; 6023d0407baSopenharmony_ci break; 6033d0407baSopenharmony_ci } 6043d0407baSopenharmony_ci 6053d0407baSopenharmony_ci memset(&sec, 0, sizeof(sec)); 6063d0407baSopenharmony_ci if (chan->conn) { 6073d0407baSopenharmony_ci sec.level = chan->conn->hcon->sec_level; 6083d0407baSopenharmony_ci 6093d0407baSopenharmony_ci if (sk->sk_state == BT_CONNECTED) { 6103d0407baSopenharmony_ci sec.key_size = chan->conn->hcon->enc_key_size; 6113d0407baSopenharmony_ci } 6123d0407baSopenharmony_ci } else { 6133d0407baSopenharmony_ci sec.level = chan->sec_level; 6143d0407baSopenharmony_ci } 6153d0407baSopenharmony_ci 6163d0407baSopenharmony_ci len = min_t(unsigned int, len, sizeof(sec)); 6173d0407baSopenharmony_ci if (copy_to_user(optval, (char *)&sec, len)) { 6183d0407baSopenharmony_ci err = -EFAULT; 6193d0407baSopenharmony_ci } 6203d0407baSopenharmony_ci 6213d0407baSopenharmony_ci break; 6223d0407baSopenharmony_ci 6233d0407baSopenharmony_ci case BT_DEFER_SETUP: 6243d0407baSopenharmony_ci if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { 6253d0407baSopenharmony_ci err = -EINVAL; 6263d0407baSopenharmony_ci break; 6273d0407baSopenharmony_ci } 6283d0407baSopenharmony_ci 6293d0407baSopenharmony_ci if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), (u32 __user *)optval)) { 6303d0407baSopenharmony_ci err = -EFAULT; 6313d0407baSopenharmony_ci } 6323d0407baSopenharmony_ci 6333d0407baSopenharmony_ci break; 6343d0407baSopenharmony_ci 6353d0407baSopenharmony_ci case BT_FLUSHABLE: 6363d0407baSopenharmony_ci if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags), (u32 __user *)optval)) { 6373d0407baSopenharmony_ci err = -EFAULT; 6383d0407baSopenharmony_ci } 6393d0407baSopenharmony_ci 6403d0407baSopenharmony_ci break; 6413d0407baSopenharmony_ci 6423d0407baSopenharmony_ci case BT_POWER: 6433d0407baSopenharmony_ci if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM && sk->sk_type != SOCK_RAW) { 6443d0407baSopenharmony_ci err = -EINVAL; 6453d0407baSopenharmony_ci break; 6463d0407baSopenharmony_ci } 6473d0407baSopenharmony_ci 6483d0407baSopenharmony_ci pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags); 6493d0407baSopenharmony_ci 6503d0407baSopenharmony_ci len = min_t(unsigned int, len, sizeof(pwr)); 6513d0407baSopenharmony_ci if (copy_to_user(optval, (char *)&pwr, len)) { 6523d0407baSopenharmony_ci err = -EFAULT; 6533d0407baSopenharmony_ci } 6543d0407baSopenharmony_ci 6553d0407baSopenharmony_ci break; 6563d0407baSopenharmony_ci 6573d0407baSopenharmony_ci case BT_CHANNEL_POLICY: 6583d0407baSopenharmony_ci if (put_user(chan->chan_policy, (u32 __user *)optval)) { 6593d0407baSopenharmony_ci err = -EFAULT; 6603d0407baSopenharmony_ci } 6613d0407baSopenharmony_ci break; 6623d0407baSopenharmony_ci 6633d0407baSopenharmony_ci case BT_SNDMTU: 6643d0407baSopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) { 6653d0407baSopenharmony_ci err = -EINVAL; 6663d0407baSopenharmony_ci break; 6673d0407baSopenharmony_ci } 6683d0407baSopenharmony_ci 6693d0407baSopenharmony_ci if (sk->sk_state != BT_CONNECTED) { 6703d0407baSopenharmony_ci err = -ENOTCONN; 6713d0407baSopenharmony_ci break; 6723d0407baSopenharmony_ci } 6733d0407baSopenharmony_ci 6743d0407baSopenharmony_ci if (put_user(chan->omtu, (u16 __user *)optval)) { 6753d0407baSopenharmony_ci err = -EFAULT; 6763d0407baSopenharmony_ci } 6773d0407baSopenharmony_ci break; 6783d0407baSopenharmony_ci 6793d0407baSopenharmony_ci case BT_RCVMTU: 6803d0407baSopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) { 6813d0407baSopenharmony_ci err = -EINVAL; 6823d0407baSopenharmony_ci break; 6833d0407baSopenharmony_ci } 6843d0407baSopenharmony_ci 6853d0407baSopenharmony_ci if (put_user(chan->imtu, (u16 __user *)optval)) { 6863d0407baSopenharmony_ci err = -EFAULT; 6873d0407baSopenharmony_ci } 6883d0407baSopenharmony_ci break; 6893d0407baSopenharmony_ci 6903d0407baSopenharmony_ci case BT_PHY: 6913d0407baSopenharmony_ci if (sk->sk_state != BT_CONNECTED) { 6923d0407baSopenharmony_ci err = -ENOTCONN; 6933d0407baSopenharmony_ci break; 6943d0407baSopenharmony_ci } 6953d0407baSopenharmony_ci 6963d0407baSopenharmony_ci phys = hci_conn_get_phy(chan->conn->hcon); 6973d0407baSopenharmony_ci 6983d0407baSopenharmony_ci if (put_user(phys, (u32 __user *)optval)) { 6993d0407baSopenharmony_ci err = -EFAULT; 7003d0407baSopenharmony_ci } 7013d0407baSopenharmony_ci break; 7023d0407baSopenharmony_ci 7033d0407baSopenharmony_ci case BT_MODE: 7043d0407baSopenharmony_ci if (!enable_ecred) { 7053d0407baSopenharmony_ci err = -ENOPROTOOPT; 7063d0407baSopenharmony_ci break; 7073d0407baSopenharmony_ci } 7083d0407baSopenharmony_ci 7093d0407baSopenharmony_ci if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { 7103d0407baSopenharmony_ci err = -EINVAL; 7113d0407baSopenharmony_ci break; 7123d0407baSopenharmony_ci } 7133d0407baSopenharmony_ci 7143d0407baSopenharmony_ci mode = l2cap_get_mode(chan); 7153d0407baSopenharmony_ci if (mode < 0) { 7163d0407baSopenharmony_ci err = mode; 7173d0407baSopenharmony_ci break; 7183d0407baSopenharmony_ci } 7193d0407baSopenharmony_ci 7203d0407baSopenharmony_ci if (put_user(mode, (u8 __user *)optval)) { 7213d0407baSopenharmony_ci err = -EFAULT; 7223d0407baSopenharmony_ci } 7233d0407baSopenharmony_ci break; 7243d0407baSopenharmony_ci 7253d0407baSopenharmony_ci default: 7263d0407baSopenharmony_ci err = -ENOPROTOOPT; 7273d0407baSopenharmony_ci break; 7283d0407baSopenharmony_ci } 7293d0407baSopenharmony_ci 7303d0407baSopenharmony_ci release_sock(sk); 7313d0407baSopenharmony_ci return err; 7323d0407baSopenharmony_ci} 7333d0407baSopenharmony_ci 7343d0407baSopenharmony_cistatic bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu) 7353d0407baSopenharmony_ci{ 7363d0407baSopenharmony_ci switch (chan->scid) { 7373d0407baSopenharmony_ci case L2CAP_CID_ATT: 7383d0407baSopenharmony_ci if (mtu < L2CAP_LE_MIN_MTU) { 7393d0407baSopenharmony_ci return false; 7403d0407baSopenharmony_ci } 7413d0407baSopenharmony_ci break; 7423d0407baSopenharmony_ci 7433d0407baSopenharmony_ci default: 7443d0407baSopenharmony_ci if (mtu < L2CAP_DEFAULT_MIN_MTU) { 7453d0407baSopenharmony_ci return false; 7463d0407baSopenharmony_ci } 7473d0407baSopenharmony_ci } 7483d0407baSopenharmony_ci 7493d0407baSopenharmony_ci return true; 7503d0407baSopenharmony_ci} 7513d0407baSopenharmony_ci 7523d0407baSopenharmony_cistatic int l2cap_sock_setsockopt_old(struct socket *sock, int optname, sockptr_t optval, unsigned int optlen) 7533d0407baSopenharmony_ci{ 7543d0407baSopenharmony_ci struct sock *sk = sock->sk; 7553d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 7563d0407baSopenharmony_ci struct l2cap_options opts; 7573d0407baSopenharmony_ci int len, err = 0; 7583d0407baSopenharmony_ci u32 opt; 7593d0407baSopenharmony_ci 7603d0407baSopenharmony_ci BT_DBG("sk %p", sk); 7613d0407baSopenharmony_ci 7623d0407baSopenharmony_ci lock_sock(sk); 7633d0407baSopenharmony_ci 7643d0407baSopenharmony_ci switch (optname) { 7653d0407baSopenharmony_ci case L2CAP_OPTIONS: 7663d0407baSopenharmony_ci if (bdaddr_type_is_le(chan->src_type)) { 7673d0407baSopenharmony_ci err = -EINVAL; 7683d0407baSopenharmony_ci break; 7693d0407baSopenharmony_ci } 7703d0407baSopenharmony_ci 7713d0407baSopenharmony_ci if (sk->sk_state == BT_CONNECTED) { 7723d0407baSopenharmony_ci err = -EINVAL; 7733d0407baSopenharmony_ci break; 7743d0407baSopenharmony_ci } 7753d0407baSopenharmony_ci 7763d0407baSopenharmony_ci opts.imtu = chan->imtu; 7773d0407baSopenharmony_ci opts.omtu = chan->omtu; 7783d0407baSopenharmony_ci opts.flush_to = chan->flush_to; 7793d0407baSopenharmony_ci opts.mode = chan->mode; 7803d0407baSopenharmony_ci opts.fcs = chan->fcs; 7813d0407baSopenharmony_ci opts.max_tx = chan->max_tx; 7823d0407baSopenharmony_ci opts.txwin_size = chan->tx_win; 7833d0407baSopenharmony_ci 7843d0407baSopenharmony_ci len = min_t(unsigned int, sizeof(opts), optlen); 7853d0407baSopenharmony_ci if (copy_from_sockptr(&opts, optval, len)) { 7863d0407baSopenharmony_ci err = -EFAULT; 7873d0407baSopenharmony_ci break; 7883d0407baSopenharmony_ci } 7893d0407baSopenharmony_ci 7903d0407baSopenharmony_ci if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) { 7913d0407baSopenharmony_ci err = -EINVAL; 7923d0407baSopenharmony_ci break; 7933d0407baSopenharmony_ci } 7943d0407baSopenharmony_ci 7953d0407baSopenharmony_ci if (!l2cap_valid_mtu(chan, opts.imtu)) { 7963d0407baSopenharmony_ci err = -EINVAL; 7973d0407baSopenharmony_ci break; 7983d0407baSopenharmony_ci } 7993d0407baSopenharmony_ci 8003d0407baSopenharmony_ci /* Only BR/EDR modes are supported here */ 8013d0407baSopenharmony_ci switch (opts.mode) { 8023d0407baSopenharmony_ci case L2CAP_MODE_BASIC: 8033d0407baSopenharmony_ci clear_bit(CONF_STATE2_DEVICE, &chan->conf_state); 8043d0407baSopenharmony_ci break; 8053d0407baSopenharmony_ci case L2CAP_MODE_ERTM: 8063d0407baSopenharmony_ci case L2CAP_MODE_STREAMING: 8073d0407baSopenharmony_ci if (!disable_ertm) { 8083d0407baSopenharmony_ci break; 8093d0407baSopenharmony_ci } 8103d0407baSopenharmony_ci fallthrough; 8113d0407baSopenharmony_ci default: 8123d0407baSopenharmony_ci err = -EINVAL; 8133d0407baSopenharmony_ci break; 8143d0407baSopenharmony_ci } 8153d0407baSopenharmony_ci 8163d0407baSopenharmony_ci if (err < 0) { 8173d0407baSopenharmony_ci break; 8183d0407baSopenharmony_ci } 8193d0407baSopenharmony_ci 8203d0407baSopenharmony_ci chan->mode = opts.mode; 8213d0407baSopenharmony_ci 8223d0407baSopenharmony_ci BT_DBG("mode 0x%2.2x", chan->mode); 8233d0407baSopenharmony_ci 8243d0407baSopenharmony_ci chan->imtu = opts.imtu; 8253d0407baSopenharmony_ci chan->omtu = opts.omtu; 8263d0407baSopenharmony_ci chan->fcs = opts.fcs; 8273d0407baSopenharmony_ci chan->max_tx = opts.max_tx; 8283d0407baSopenharmony_ci chan->tx_win = opts.txwin_size; 8293d0407baSopenharmony_ci chan->flush_to = opts.flush_to; 8303d0407baSopenharmony_ci break; 8313d0407baSopenharmony_ci 8323d0407baSopenharmony_ci case L2CAP_LM: 8333d0407baSopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(u32))) { 8343d0407baSopenharmony_ci err = -EFAULT; 8353d0407baSopenharmony_ci break; 8363d0407baSopenharmony_ci } 8373d0407baSopenharmony_ci 8383d0407baSopenharmony_ci if (opt & L2CAP_LM_FIPS) { 8393d0407baSopenharmony_ci err = -EINVAL; 8403d0407baSopenharmony_ci break; 8413d0407baSopenharmony_ci } 8423d0407baSopenharmony_ci 8433d0407baSopenharmony_ci if (opt & L2CAP_LM_AUTH) { 8443d0407baSopenharmony_ci chan->sec_level = BT_SECURITY_LOW; 8453d0407baSopenharmony_ci } 8463d0407baSopenharmony_ci if (opt & L2CAP_LM_ENCRYPT) { 8473d0407baSopenharmony_ci chan->sec_level = BT_SECURITY_MEDIUM; 8483d0407baSopenharmony_ci } 8493d0407baSopenharmony_ci if (opt & L2CAP_LM_SECURE) { 8503d0407baSopenharmony_ci chan->sec_level = BT_SECURITY_HIGH; 8513d0407baSopenharmony_ci } 8523d0407baSopenharmony_ci 8533d0407baSopenharmony_ci if (opt & L2CAP_LM_MASTER) { 8543d0407baSopenharmony_ci set_bit(FLAG_ROLE_SWITCH, &chan->flags); 8553d0407baSopenharmony_ci } else { 8563d0407baSopenharmony_ci clear_bit(FLAG_ROLE_SWITCH, &chan->flags); 8573d0407baSopenharmony_ci } 8583d0407baSopenharmony_ci 8593d0407baSopenharmony_ci if (opt & L2CAP_LM_RELIABLE) { 8603d0407baSopenharmony_ci set_bit(FLAG_FORCE_RELIABLE, &chan->flags); 8613d0407baSopenharmony_ci } else { 8623d0407baSopenharmony_ci clear_bit(FLAG_FORCE_RELIABLE, &chan->flags); 8633d0407baSopenharmony_ci } 8643d0407baSopenharmony_ci break; 8653d0407baSopenharmony_ci 8663d0407baSopenharmony_ci default: 8673d0407baSopenharmony_ci err = -ENOPROTOOPT; 8683d0407baSopenharmony_ci break; 8693d0407baSopenharmony_ci } 8703d0407baSopenharmony_ci 8713d0407baSopenharmony_ci release_sock(sk); 8723d0407baSopenharmony_ci return err; 8733d0407baSopenharmony_ci} 8743d0407baSopenharmony_ci 8753d0407baSopenharmony_cistatic int l2cap_set_mode(struct l2cap_chan *chan, u8 mode) 8763d0407baSopenharmony_ci{ 8773d0407baSopenharmony_ci switch (mode) { 8783d0407baSopenharmony_ci case BT_MODE_BASIC: 8793d0407baSopenharmony_ci if (bdaddr_type_is_le(chan->src_type)) { 8803d0407baSopenharmony_ci return -EINVAL; 8813d0407baSopenharmony_ci } 8823d0407baSopenharmony_ci mode = L2CAP_MODE_BASIC; 8833d0407baSopenharmony_ci clear_bit(CONF_STATE2_DEVICE, &chan->conf_state); 8843d0407baSopenharmony_ci break; 8853d0407baSopenharmony_ci case BT_MODE_ERTM: 8863d0407baSopenharmony_ci if (!disable_ertm || bdaddr_type_is_le(chan->src_type)) { 8873d0407baSopenharmony_ci return -EINVAL; 8883d0407baSopenharmony_ci } 8893d0407baSopenharmony_ci mode = L2CAP_MODE_ERTM; 8903d0407baSopenharmony_ci break; 8913d0407baSopenharmony_ci case BT_MODE_STREAMING: 8923d0407baSopenharmony_ci if (!disable_ertm || bdaddr_type_is_le(chan->src_type)) { 8933d0407baSopenharmony_ci return -EINVAL; 8943d0407baSopenharmony_ci } 8953d0407baSopenharmony_ci mode = L2CAP_MODE_STREAMING; 8963d0407baSopenharmony_ci break; 8973d0407baSopenharmony_ci case BT_MODE_LE_FLOWCTL: 8983d0407baSopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) { 8993d0407baSopenharmony_ci return -EINVAL; 9003d0407baSopenharmony_ci } 9013d0407baSopenharmony_ci mode = L2CAP_MODE_LE_FLOWCTL; 9023d0407baSopenharmony_ci break; 9033d0407baSopenharmony_ci case BT_MODE_EXT_FLOWCTL: 9043d0407baSopenharmony_ci /* Add support for ECRED PDUs to BR/EDR */ 9053d0407baSopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) { 9063d0407baSopenharmony_ci return -EINVAL; 9073d0407baSopenharmony_ci } 9083d0407baSopenharmony_ci mode = L2CAP_MODE_EXT_FLOWCTL; 9093d0407baSopenharmony_ci break; 9103d0407baSopenharmony_ci default: 9113d0407baSopenharmony_ci return -EINVAL; 9123d0407baSopenharmony_ci } 9133d0407baSopenharmony_ci 9143d0407baSopenharmony_ci chan->mode = mode; 9153d0407baSopenharmony_ci 9163d0407baSopenharmony_ci return 0; 9173d0407baSopenharmony_ci} 9183d0407baSopenharmony_ci 9193d0407baSopenharmony_cistatic int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, sockptr_t optval, unsigned int optlen) 9203d0407baSopenharmony_ci{ 9213d0407baSopenharmony_ci struct sock *sk = sock->sk; 9223d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 9233d0407baSopenharmony_ci struct bt_security sec; 9243d0407baSopenharmony_ci struct bt_power pwr; 9253d0407baSopenharmony_ci struct l2cap_conn *conn; 9263d0407baSopenharmony_ci int len, err = 0; 9273d0407baSopenharmony_ci u32 opt; 9283d0407baSopenharmony_ci u16 mtu; 9293d0407baSopenharmony_ci u8 mode; 9303d0407baSopenharmony_ci 9313d0407baSopenharmony_ci BT_DBG("sk %p", sk); 9323d0407baSopenharmony_ci 9333d0407baSopenharmony_ci if (level == SOL_L2CAP) { 9343d0407baSopenharmony_ci return l2cap_sock_setsockopt_old(sock, optname, optval, optlen); 9353d0407baSopenharmony_ci } 9363d0407baSopenharmony_ci 9373d0407baSopenharmony_ci if (level != SOL_BLUETOOTH) { 9383d0407baSopenharmony_ci return -ENOPROTOOPT; 9393d0407baSopenharmony_ci } 9403d0407baSopenharmony_ci 9413d0407baSopenharmony_ci lock_sock(sk); 9423d0407baSopenharmony_ci 9433d0407baSopenharmony_ci switch (optname) { 9443d0407baSopenharmony_ci case BT_SECURITY: 9453d0407baSopenharmony_ci if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED && chan->chan_type != L2CAP_CHAN_FIXED && 9463d0407baSopenharmony_ci chan->chan_type != L2CAP_CHAN_RAW) { 9473d0407baSopenharmony_ci err = -EINVAL; 9483d0407baSopenharmony_ci break; 9493d0407baSopenharmony_ci } 9503d0407baSopenharmony_ci 9513d0407baSopenharmony_ci sec.level = BT_SECURITY_LOW; 9523d0407baSopenharmony_ci 9533d0407baSopenharmony_ci len = min_t(unsigned int, sizeof(sec), optlen); 9543d0407baSopenharmony_ci if (copy_from_sockptr(&sec, optval, len)) { 9553d0407baSopenharmony_ci err = -EFAULT; 9563d0407baSopenharmony_ci break; 9573d0407baSopenharmony_ci } 9583d0407baSopenharmony_ci 9593d0407baSopenharmony_ci if (sec.level < BT_SECURITY_LOW || sec.level > BT_SECURITY_FIPS) { 9603d0407baSopenharmony_ci err = -EINVAL; 9613d0407baSopenharmony_ci break; 9623d0407baSopenharmony_ci } 9633d0407baSopenharmony_ci 9643d0407baSopenharmony_ci chan->sec_level = sec.level; 9653d0407baSopenharmony_ci 9663d0407baSopenharmony_ci if (!chan->conn) { 9673d0407baSopenharmony_ci break; 9683d0407baSopenharmony_ci } 9693d0407baSopenharmony_ci 9703d0407baSopenharmony_ci conn = chan->conn; 9713d0407baSopenharmony_ci 9723d0407baSopenharmony_ci /* change security for LE channels */ 9733d0407baSopenharmony_ci if (chan->scid == L2CAP_CID_ATT) { 9743d0407baSopenharmony_ci if (smp_conn_security(conn->hcon, sec.level)) { 9753d0407baSopenharmony_ci err = -EINVAL; 9763d0407baSopenharmony_ci break; 9773d0407baSopenharmony_ci } 9783d0407baSopenharmony_ci 9793d0407baSopenharmony_ci set_bit(FLAG_PENDING_SECURITY, &chan->flags); 9803d0407baSopenharmony_ci sk->sk_state = BT_CONFIG; 9813d0407baSopenharmony_ci chan->state = BT_CONFIG; 9823d0407baSopenharmony_ci 9833d0407baSopenharmony_ci /* or for ACL link */ 9843d0407baSopenharmony_ci } else if ((sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) || 9853d0407baSopenharmony_ci sk->sk_state == BT_CONNECTED) { 9863d0407baSopenharmony_ci if (!l2cap_chan_check_security(chan, true)) { 9873d0407baSopenharmony_ci set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); 9883d0407baSopenharmony_ci } else { 9893d0407baSopenharmony_ci sk->sk_state_change(sk); 9903d0407baSopenharmony_ci } 9913d0407baSopenharmony_ci } else { 9923d0407baSopenharmony_ci err = -EINVAL; 9933d0407baSopenharmony_ci } 9943d0407baSopenharmony_ci break; 9953d0407baSopenharmony_ci 9963d0407baSopenharmony_ci case BT_DEFER_SETUP: 9973d0407baSopenharmony_ci if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { 9983d0407baSopenharmony_ci err = -EINVAL; 9993d0407baSopenharmony_ci break; 10003d0407baSopenharmony_ci } 10013d0407baSopenharmony_ci 10023d0407baSopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(u32))) { 10033d0407baSopenharmony_ci err = -EFAULT; 10043d0407baSopenharmony_ci break; 10053d0407baSopenharmony_ci } 10063d0407baSopenharmony_ci 10073d0407baSopenharmony_ci if (opt) { 10083d0407baSopenharmony_ci set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); 10093d0407baSopenharmony_ci set_bit(FLAG_DEFER_SETUP, &chan->flags); 10103d0407baSopenharmony_ci } else { 10113d0407baSopenharmony_ci clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); 10123d0407baSopenharmony_ci clear_bit(FLAG_DEFER_SETUP, &chan->flags); 10133d0407baSopenharmony_ci } 10143d0407baSopenharmony_ci break; 10153d0407baSopenharmony_ci 10163d0407baSopenharmony_ci case BT_FLUSHABLE: 10173d0407baSopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(u32))) { 10183d0407baSopenharmony_ci err = -EFAULT; 10193d0407baSopenharmony_ci break; 10203d0407baSopenharmony_ci } 10213d0407baSopenharmony_ci 10223d0407baSopenharmony_ci if (opt > BT_FLUSHABLE_ON) { 10233d0407baSopenharmony_ci err = -EINVAL; 10243d0407baSopenharmony_ci break; 10253d0407baSopenharmony_ci } 10263d0407baSopenharmony_ci 10273d0407baSopenharmony_ci if (opt == BT_FLUSHABLE_OFF) { 10283d0407baSopenharmony_ci conn = chan->conn; 10293d0407baSopenharmony_ci /* proceed further only when we have l2cap_conn and 10303d0407baSopenharmony_ci No Flush support in the LM */ 10313d0407baSopenharmony_ci if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) { 10323d0407baSopenharmony_ci err = -EINVAL; 10333d0407baSopenharmony_ci break; 10343d0407baSopenharmony_ci } 10353d0407baSopenharmony_ci } 10363d0407baSopenharmony_ci 10373d0407baSopenharmony_ci if (opt) { 10383d0407baSopenharmony_ci set_bit(FLAG_FLUSHABLE, &chan->flags); 10393d0407baSopenharmony_ci } else { 10403d0407baSopenharmony_ci clear_bit(FLAG_FLUSHABLE, &chan->flags); 10413d0407baSopenharmony_ci } 10423d0407baSopenharmony_ci break; 10433d0407baSopenharmony_ci 10443d0407baSopenharmony_ci case BT_POWER: 10453d0407baSopenharmony_ci if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED && chan->chan_type != L2CAP_CHAN_RAW) { 10463d0407baSopenharmony_ci err = -EINVAL; 10473d0407baSopenharmony_ci break; 10483d0407baSopenharmony_ci } 10493d0407baSopenharmony_ci 10503d0407baSopenharmony_ci pwr.force_active = BT_POWER_FORCE_ACTIVE_ON; 10513d0407baSopenharmony_ci 10523d0407baSopenharmony_ci len = min_t(unsigned int, sizeof(pwr), optlen); 10533d0407baSopenharmony_ci if (copy_from_sockptr(&pwr, optval, len)) { 10543d0407baSopenharmony_ci err = -EFAULT; 10553d0407baSopenharmony_ci break; 10563d0407baSopenharmony_ci } 10573d0407baSopenharmony_ci 10583d0407baSopenharmony_ci if (pwr.force_active) { 10593d0407baSopenharmony_ci set_bit(FLAG_FORCE_ACTIVE, &chan->flags); 10603d0407baSopenharmony_ci } else { 10613d0407baSopenharmony_ci clear_bit(FLAG_FORCE_ACTIVE, &chan->flags); 10623d0407baSopenharmony_ci } 10633d0407baSopenharmony_ci break; 10643d0407baSopenharmony_ci 10653d0407baSopenharmony_ci case BT_CHANNEL_POLICY: 10663d0407baSopenharmony_ci if (copy_from_sockptr(&opt, optval, sizeof(u32))) { 10673d0407baSopenharmony_ci err = -EFAULT; 10683d0407baSopenharmony_ci break; 10693d0407baSopenharmony_ci } 10703d0407baSopenharmony_ci 10713d0407baSopenharmony_ci if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) { 10723d0407baSopenharmony_ci err = -EINVAL; 10733d0407baSopenharmony_ci break; 10743d0407baSopenharmony_ci } 10753d0407baSopenharmony_ci 10763d0407baSopenharmony_ci if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING) { 10773d0407baSopenharmony_ci err = -EOPNOTSUPP; 10783d0407baSopenharmony_ci break; 10793d0407baSopenharmony_ci } 10803d0407baSopenharmony_ci 10813d0407baSopenharmony_ci chan->chan_policy = (u8)opt; 10823d0407baSopenharmony_ci 10833d0407baSopenharmony_ci if (sk->sk_state == BT_CONNECTED && chan->move_role == L2CAP_MOVE_ROLE_NONE) { 10843d0407baSopenharmony_ci l2cap_move_start(chan); 10853d0407baSopenharmony_ci } 10863d0407baSopenharmony_ci 10873d0407baSopenharmony_ci break; 10883d0407baSopenharmony_ci 10893d0407baSopenharmony_ci case BT_SNDMTU: 10903d0407baSopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) { 10913d0407baSopenharmony_ci err = -EINVAL; 10923d0407baSopenharmony_ci break; 10933d0407baSopenharmony_ci } 10943d0407baSopenharmony_ci 10953d0407baSopenharmony_ci /* Setting is not supported as it's the remote side that 10963d0407baSopenharmony_ci * decides this. 10973d0407baSopenharmony_ci */ 10983d0407baSopenharmony_ci err = -EPERM; 10993d0407baSopenharmony_ci break; 11003d0407baSopenharmony_ci 11013d0407baSopenharmony_ci case BT_RCVMTU: 11023d0407baSopenharmony_ci if (!bdaddr_type_is_le(chan->src_type)) { 11033d0407baSopenharmony_ci err = -EINVAL; 11043d0407baSopenharmony_ci break; 11053d0407baSopenharmony_ci } 11063d0407baSopenharmony_ci 11073d0407baSopenharmony_ci if (chan->mode == L2CAP_MODE_LE_FLOWCTL && sk->sk_state == BT_CONNECTED) { 11083d0407baSopenharmony_ci err = -EISCONN; 11093d0407baSopenharmony_ci break; 11103d0407baSopenharmony_ci } 11113d0407baSopenharmony_ci 11123d0407baSopenharmony_ci if (copy_from_sockptr(&mtu, optval, sizeof(u16))) { 11133d0407baSopenharmony_ci err = -EFAULT; 11143d0407baSopenharmony_ci break; 11153d0407baSopenharmony_ci } 11163d0407baSopenharmony_ci 11173d0407baSopenharmony_ci if (chan->mode == L2CAP_MODE_EXT_FLOWCTL && sk->sk_state == BT_CONNECTED) { 11183d0407baSopenharmony_ci err = l2cap_chan_reconfigure(chan, mtu); 11193d0407baSopenharmony_ci } else { 11203d0407baSopenharmony_ci chan->imtu = mtu; 11213d0407baSopenharmony_ci } 11223d0407baSopenharmony_ci 11233d0407baSopenharmony_ci break; 11243d0407baSopenharmony_ci 11253d0407baSopenharmony_ci case BT_MODE: 11263d0407baSopenharmony_ci if (!enable_ecred) { 11273d0407baSopenharmony_ci err = -ENOPROTOOPT; 11283d0407baSopenharmony_ci break; 11293d0407baSopenharmony_ci } 11303d0407baSopenharmony_ci 11313d0407baSopenharmony_ci BT_DBG("sk->sk_state %u", sk->sk_state); 11323d0407baSopenharmony_ci 11333d0407baSopenharmony_ci if (sk->sk_state != BT_BOUND) { 11343d0407baSopenharmony_ci err = -EINVAL; 11353d0407baSopenharmony_ci break; 11363d0407baSopenharmony_ci } 11373d0407baSopenharmony_ci 11383d0407baSopenharmony_ci if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { 11393d0407baSopenharmony_ci err = -EINVAL; 11403d0407baSopenharmony_ci break; 11413d0407baSopenharmony_ci } 11423d0407baSopenharmony_ci 11433d0407baSopenharmony_ci if (copy_from_sockptr(&mode, optval, sizeof(u8))) { 11443d0407baSopenharmony_ci err = -EFAULT; 11453d0407baSopenharmony_ci break; 11463d0407baSopenharmony_ci } 11473d0407baSopenharmony_ci 11483d0407baSopenharmony_ci BT_DBG("mode %u", mode); 11493d0407baSopenharmony_ci 11503d0407baSopenharmony_ci err = l2cap_set_mode(chan, mode); 11513d0407baSopenharmony_ci if (err) { 11523d0407baSopenharmony_ci break; 11533d0407baSopenharmony_ci } 11543d0407baSopenharmony_ci 11553d0407baSopenharmony_ci BT_DBG("mode 0x%2.2x", chan->mode); 11563d0407baSopenharmony_ci 11573d0407baSopenharmony_ci break; 11583d0407baSopenharmony_ci 11593d0407baSopenharmony_ci default: 11603d0407baSopenharmony_ci err = -ENOPROTOOPT; 11613d0407baSopenharmony_ci break; 11623d0407baSopenharmony_ci } 11633d0407baSopenharmony_ci 11643d0407baSopenharmony_ci release_sock(sk); 11653d0407baSopenharmony_ci return err; 11663d0407baSopenharmony_ci} 11673d0407baSopenharmony_ci 11683d0407baSopenharmony_cistatic int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) 11693d0407baSopenharmony_ci{ 11703d0407baSopenharmony_ci struct sock *sk = sock->sk; 11713d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 11723d0407baSopenharmony_ci int err; 11733d0407baSopenharmony_ci 11743d0407baSopenharmony_ci BT_DBG("sock %p, sk %p", sock, sk); 11753d0407baSopenharmony_ci 11763d0407baSopenharmony_ci err = sock_error(sk); 11773d0407baSopenharmony_ci if (err) { 11783d0407baSopenharmony_ci return err; 11793d0407baSopenharmony_ci } 11803d0407baSopenharmony_ci 11813d0407baSopenharmony_ci if (msg->msg_flags & MSG_OOB) { 11823d0407baSopenharmony_ci return -EOPNOTSUPP; 11833d0407baSopenharmony_ci } 11843d0407baSopenharmony_ci 11853d0407baSopenharmony_ci if (sk->sk_state != BT_CONNECTED) { 11863d0407baSopenharmony_ci return -ENOTCONN; 11873d0407baSopenharmony_ci } 11883d0407baSopenharmony_ci 11893d0407baSopenharmony_ci lock_sock(sk); 11903d0407baSopenharmony_ci err = bt_sock_wait_ready(sk, msg->msg_flags); 11913d0407baSopenharmony_ci release_sock(sk); 11923d0407baSopenharmony_ci if (err) { 11933d0407baSopenharmony_ci return err; 11943d0407baSopenharmony_ci } 11953d0407baSopenharmony_ci 11963d0407baSopenharmony_ci l2cap_chan_lock(chan); 11973d0407baSopenharmony_ci err = l2cap_chan_send(chan, msg, len); 11983d0407baSopenharmony_ci l2cap_chan_unlock(chan); 11993d0407baSopenharmony_ci 12003d0407baSopenharmony_ci return err; 12013d0407baSopenharmony_ci} 12023d0407baSopenharmony_ci 12033d0407baSopenharmony_cistatic int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags) 12043d0407baSopenharmony_ci{ 12053d0407baSopenharmony_ci struct sock *sk = sock->sk; 12063d0407baSopenharmony_ci struct l2cap_pinfo *pi = l2cap_pi(sk); 12073d0407baSopenharmony_ci int err; 12083d0407baSopenharmony_ci 12093d0407baSopenharmony_ci lock_sock(sk); 12103d0407baSopenharmony_ci 12113d0407baSopenharmony_ci if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { 12123d0407baSopenharmony_ci if (pi->chan->mode == L2CAP_MODE_EXT_FLOWCTL) { 12133d0407baSopenharmony_ci sk->sk_state = BT_CONNECTED; 12143d0407baSopenharmony_ci pi->chan->state = BT_CONNECTED; 12153d0407baSopenharmony_ci __l2cap_ecred_conn_rsp_defer(pi->chan); 12163d0407baSopenharmony_ci } else if (bdaddr_type_is_le(pi->chan->src_type)) { 12173d0407baSopenharmony_ci sk->sk_state = BT_CONNECTED; 12183d0407baSopenharmony_ci pi->chan->state = BT_CONNECTED; 12193d0407baSopenharmony_ci __l2cap_le_connect_rsp_defer(pi->chan); 12203d0407baSopenharmony_ci } else { 12213d0407baSopenharmony_ci sk->sk_state = BT_CONFIG; 12223d0407baSopenharmony_ci pi->chan->state = BT_CONFIG; 12233d0407baSopenharmony_ci __l2cap_connect_rsp_defer(pi->chan); 12243d0407baSopenharmony_ci } 12253d0407baSopenharmony_ci 12263d0407baSopenharmony_ci err = 0; 12273d0407baSopenharmony_ci goto done; 12283d0407baSopenharmony_ci } 12293d0407baSopenharmony_ci 12303d0407baSopenharmony_ci release_sock(sk); 12313d0407baSopenharmony_ci 12323d0407baSopenharmony_ci if (sock->type == SOCK_STREAM) { 12333d0407baSopenharmony_ci err = bt_sock_stream_recvmsg(sock, msg, len, flags); 12343d0407baSopenharmony_ci } else { 12353d0407baSopenharmony_ci err = bt_sock_recvmsg(sock, msg, len, flags); 12363d0407baSopenharmony_ci } 12373d0407baSopenharmony_ci 12383d0407baSopenharmony_ci if (pi->chan->mode != L2CAP_MODE_ERTM) { 12393d0407baSopenharmony_ci return err; 12403d0407baSopenharmony_ci } 12413d0407baSopenharmony_ci 12423d0407baSopenharmony_ci /* Attempt to put pending rx data in the socket buffer */ 12433d0407baSopenharmony_ci 12443d0407baSopenharmony_ci lock_sock(sk); 12453d0407baSopenharmony_ci 12463d0407baSopenharmony_ci if (!test_bit(CONN_LOCAL_BUSY, &pi->chan->conn_state)) { 12473d0407baSopenharmony_ci goto done; 12483d0407baSopenharmony_ci } 12493d0407baSopenharmony_ci 12503d0407baSopenharmony_ci if (pi->rx_busy_skb) { 12513d0407baSopenharmony_ci if (!__sock_queue_rcv_skb(sk, pi->rx_busy_skb)) { 12523d0407baSopenharmony_ci pi->rx_busy_skb = NULL; 12533d0407baSopenharmony_ci } else { 12543d0407baSopenharmony_ci goto done; 12553d0407baSopenharmony_ci } 12563d0407baSopenharmony_ci } 12573d0407baSopenharmony_ci 12583d0407baSopenharmony_ci /* Restore data flow when half of the receive buffer is 12593d0407baSopenharmony_ci * available. This avoids resending large numbers of 12603d0407baSopenharmony_ci * frames. 12613d0407baSopenharmony_ci */ 12623d0407baSopenharmony_ci if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf >> 1) { 12633d0407baSopenharmony_ci l2cap_chan_busy(pi->chan, 0); 12643d0407baSopenharmony_ci } 12653d0407baSopenharmony_ci 12663d0407baSopenharmony_cidone: 12673d0407baSopenharmony_ci release_sock(sk); 12683d0407baSopenharmony_ci return err; 12693d0407baSopenharmony_ci} 12703d0407baSopenharmony_ci 12713d0407baSopenharmony_ci/* Kill socket (only if zapped and orphan) 12723d0407baSopenharmony_ci * Must be called on unlocked socket, with l2cap channel lock. 12733d0407baSopenharmony_ci */ 12743d0407baSopenharmony_cistatic void l2cap_sock_kill(struct sock *sk) 12753d0407baSopenharmony_ci{ 12763d0407baSopenharmony_ci if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket) { 12773d0407baSopenharmony_ci return; 12783d0407baSopenharmony_ci } 12793d0407baSopenharmony_ci 12803d0407baSopenharmony_ci BT_DBG("sk %p state %s", sk, state_to_string(sk->sk_state)); 12813d0407baSopenharmony_ci 12823d0407baSopenharmony_ci /* Kill poor orphan */ 12833d0407baSopenharmony_ci 12843d0407baSopenharmony_ci l2cap_chan_put(l2cap_pi(sk)->chan); 12853d0407baSopenharmony_ci sock_set_flag(sk, SOCK_DEAD); 12863d0407baSopenharmony_ci sock_put(sk); 12873d0407baSopenharmony_ci} 12883d0407baSopenharmony_ci 12893d0407baSopenharmony_cistatic int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan) 12903d0407baSopenharmony_ci{ 12913d0407baSopenharmony_ci DECLARE_WAITQUEUE(wait, current); 12923d0407baSopenharmony_ci int err = 0; 12933d0407baSopenharmony_ci int timeo = L2CAP_WAIT_ACK_POLL_PERIOD; 12943d0407baSopenharmony_ci /* Timeout to prevent infinite loop */ 12953d0407baSopenharmony_ci unsigned long timeout = jiffies + L2CAP_WAIT_ACK_TIMEOUT; 12963d0407baSopenharmony_ci 12973d0407baSopenharmony_ci add_wait_queue(sk_sleep(sk), &wait); 12983d0407baSopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 12993d0407baSopenharmony_ci do { 13003d0407baSopenharmony_ci BT_DBG("Waiting for %d ACKs, timeout %04d ms", chan->unacked_frames, 13013d0407baSopenharmony_ci time_after(jiffies, timeout) ? 0 : jiffies_to_msecs(timeout - jiffies)); 13023d0407baSopenharmony_ci 13033d0407baSopenharmony_ci if (!timeo) { 13043d0407baSopenharmony_ci timeo = L2CAP_WAIT_ACK_POLL_PERIOD; 13053d0407baSopenharmony_ci } 13063d0407baSopenharmony_ci 13073d0407baSopenharmony_ci if (signal_pending(current)) { 13083d0407baSopenharmony_ci err = sock_intr_errno(timeo); 13093d0407baSopenharmony_ci break; 13103d0407baSopenharmony_ci } 13113d0407baSopenharmony_ci 13123d0407baSopenharmony_ci release_sock(sk); 13133d0407baSopenharmony_ci timeo = schedule_timeout(timeo); 13143d0407baSopenharmony_ci lock_sock(sk); 13153d0407baSopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 13163d0407baSopenharmony_ci 13173d0407baSopenharmony_ci err = sock_error(sk); 13183d0407baSopenharmony_ci if (err) { 13193d0407baSopenharmony_ci break; 13203d0407baSopenharmony_ci } 13213d0407baSopenharmony_ci 13223d0407baSopenharmony_ci if (time_after(jiffies, timeout)) { 13233d0407baSopenharmony_ci err = -ENOLINK; 13243d0407baSopenharmony_ci break; 13253d0407baSopenharmony_ci } 13263d0407baSopenharmony_ci } while (chan->unacked_frames > 0 && chan->state == BT_CONNECTED); 13273d0407baSopenharmony_ci 13283d0407baSopenharmony_ci set_current_state(TASK_RUNNING); 13293d0407baSopenharmony_ci remove_wait_queue(sk_sleep(sk), &wait); 13303d0407baSopenharmony_ci return err; 13313d0407baSopenharmony_ci} 13323d0407baSopenharmony_ci 13333d0407baSopenharmony_cistatic int l2cap_sock_shutdown(struct socket *sock, int how) 13343d0407baSopenharmony_ci{ 13353d0407baSopenharmony_ci struct sock *sk = sock->sk; 13363d0407baSopenharmony_ci struct l2cap_chan *chan; 13373d0407baSopenharmony_ci struct l2cap_conn *conn; 13383d0407baSopenharmony_ci int err = 0; 13393d0407baSopenharmony_ci 13403d0407baSopenharmony_ci BT_DBG("sock %p, sk %p, how %d", sock, sk, how); 13413d0407baSopenharmony_ci 13423d0407baSopenharmony_ci /* 'how' parameter is mapped to sk_shutdown as follows: 13433d0407baSopenharmony_ci * SHUT_RD (0) --> RCV_SHUTDOWN (1) 13443d0407baSopenharmony_ci * SHUT_WR (1) --> SEND_SHUTDOWN (2) 13453d0407baSopenharmony_ci * SHUT_RDWR (2) --> SHUTDOWN_MASK (3) 13463d0407baSopenharmony_ci */ 13473d0407baSopenharmony_ci how++; 13483d0407baSopenharmony_ci 13493d0407baSopenharmony_ci if (!sk) { 13503d0407baSopenharmony_ci return 0; 13513d0407baSopenharmony_ci } 13523d0407baSopenharmony_ci 13533d0407baSopenharmony_ci lock_sock(sk); 13543d0407baSopenharmony_ci 13553d0407baSopenharmony_ci if ((sk->sk_shutdown & how) == how) { 13563d0407baSopenharmony_ci goto shutdown_already; 13573d0407baSopenharmony_ci } 13583d0407baSopenharmony_ci 13593d0407baSopenharmony_ci BT_DBG("Handling sock shutdown"); 13603d0407baSopenharmony_ci 13613d0407baSopenharmony_ci /* prevent sk structure from being freed whilst unlocked */ 13623d0407baSopenharmony_ci sock_hold(sk); 13633d0407baSopenharmony_ci 13643d0407baSopenharmony_ci chan = l2cap_pi(sk)->chan; 13653d0407baSopenharmony_ci /* prevent chan structure from being freed whilst unlocked */ 13663d0407baSopenharmony_ci l2cap_chan_hold(chan); 13673d0407baSopenharmony_ci 13683d0407baSopenharmony_ci BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); 13693d0407baSopenharmony_ci 13703d0407baSopenharmony_ci if (chan->mode == L2CAP_MODE_ERTM && chan->unacked_frames > 0 && chan->state == BT_CONNECTED) { 13713d0407baSopenharmony_ci err = __l2cap_wait_ack(sk, chan); 13723d0407baSopenharmony_ci 13733d0407baSopenharmony_ci /* After waiting for ACKs, check whether shutdown 13743d0407baSopenharmony_ci * has already been actioned to close the L2CAP 13753d0407baSopenharmony_ci * link such as by l2cap_disconnection_req(). 13763d0407baSopenharmony_ci */ 13773d0407baSopenharmony_ci if ((sk->sk_shutdown & how) == how) { 13783d0407baSopenharmony_ci goto shutdown_matched; 13793d0407baSopenharmony_ci } 13803d0407baSopenharmony_ci } 13813d0407baSopenharmony_ci 13823d0407baSopenharmony_ci /* Try setting the RCV_SHUTDOWN bit, return early if SEND_SHUTDOWN 13833d0407baSopenharmony_ci * is already set 13843d0407baSopenharmony_ci */ 13853d0407baSopenharmony_ci if ((how & RCV_SHUTDOWN) && !(sk->sk_shutdown & RCV_SHUTDOWN)) { 13863d0407baSopenharmony_ci sk->sk_shutdown |= RCV_SHUTDOWN; 13873d0407baSopenharmony_ci if ((sk->sk_shutdown & how) == how) { 13883d0407baSopenharmony_ci goto shutdown_matched; 13893d0407baSopenharmony_ci } 13903d0407baSopenharmony_ci } 13913d0407baSopenharmony_ci 13923d0407baSopenharmony_ci sk->sk_shutdown |= SEND_SHUTDOWN; 13933d0407baSopenharmony_ci release_sock(sk); 13943d0407baSopenharmony_ci 13953d0407baSopenharmony_ci l2cap_chan_lock(chan); 13963d0407baSopenharmony_ci conn = chan->conn; 13973d0407baSopenharmony_ci if (conn) { 13983d0407baSopenharmony_ci /* prevent conn structure from being freed */ 13993d0407baSopenharmony_ci l2cap_conn_get(conn); 14003d0407baSopenharmony_ci } 14013d0407baSopenharmony_ci l2cap_chan_unlock(chan); 14023d0407baSopenharmony_ci 14033d0407baSopenharmony_ci if (conn) { 14043d0407baSopenharmony_ci /* mutex lock must be taken before l2cap_chan_lock() */ 14053d0407baSopenharmony_ci mutex_lock(&conn->chan_lock); 14063d0407baSopenharmony_ci } 14073d0407baSopenharmony_ci 14083d0407baSopenharmony_ci l2cap_chan_lock(chan); 14093d0407baSopenharmony_ci l2cap_chan_close(chan, 0); 14103d0407baSopenharmony_ci l2cap_chan_unlock(chan); 14113d0407baSopenharmony_ci 14123d0407baSopenharmony_ci if (conn) { 14133d0407baSopenharmony_ci mutex_unlock(&conn->chan_lock); 14143d0407baSopenharmony_ci l2cap_conn_put(conn); 14153d0407baSopenharmony_ci } 14163d0407baSopenharmony_ci 14173d0407baSopenharmony_ci lock_sock(sk); 14183d0407baSopenharmony_ci 14193d0407baSopenharmony_ci if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && !(current->flags & PF_EXITING)) { 14203d0407baSopenharmony_ci err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime); 14213d0407baSopenharmony_ci } 14223d0407baSopenharmony_ci 14233d0407baSopenharmony_cishutdown_matched: 14243d0407baSopenharmony_ci l2cap_chan_put(chan); 14253d0407baSopenharmony_ci sock_put(sk); 14263d0407baSopenharmony_ci 14273d0407baSopenharmony_cishutdown_already: 14283d0407baSopenharmony_ci if (!err && sk->sk_err) { 14293d0407baSopenharmony_ci err = -sk->sk_err; 14303d0407baSopenharmony_ci } 14313d0407baSopenharmony_ci 14323d0407baSopenharmony_ci release_sock(sk); 14333d0407baSopenharmony_ci 14343d0407baSopenharmony_ci BT_DBG("Sock shutdown complete err: %d", err); 14353d0407baSopenharmony_ci 14363d0407baSopenharmony_ci return err; 14373d0407baSopenharmony_ci} 14383d0407baSopenharmony_ci 14393d0407baSopenharmony_cistatic int l2cap_sock_release(struct socket *sock) 14403d0407baSopenharmony_ci{ 14413d0407baSopenharmony_ci struct sock *sk = sock->sk; 14423d0407baSopenharmony_ci int err; 14433d0407baSopenharmony_ci struct l2cap_chan *chan; 14443d0407baSopenharmony_ci 14453d0407baSopenharmony_ci BT_DBG("sock %p, sk %p", sock, sk); 14463d0407baSopenharmony_ci 14473d0407baSopenharmony_ci if (!sk) { 14483d0407baSopenharmony_ci return 0; 14493d0407baSopenharmony_ci } 14503d0407baSopenharmony_ci 14513d0407baSopenharmony_ci bt_sock_unlink(&l2cap_sk_list, sk); 14523d0407baSopenharmony_ci 14533d0407baSopenharmony_ci err = l2cap_sock_shutdown(sock, SHUT_RDWR); 14543d0407baSopenharmony_ci chan = l2cap_pi(sk)->chan; 14553d0407baSopenharmony_ci 14563d0407baSopenharmony_ci l2cap_chan_hold(chan); 14573d0407baSopenharmony_ci l2cap_chan_lock(chan); 14583d0407baSopenharmony_ci 14593d0407baSopenharmony_ci sock_orphan(sk); 14603d0407baSopenharmony_ci l2cap_sock_kill(sk); 14613d0407baSopenharmony_ci 14623d0407baSopenharmony_ci l2cap_chan_unlock(chan); 14633d0407baSopenharmony_ci l2cap_chan_put(chan); 14643d0407baSopenharmony_ci 14653d0407baSopenharmony_ci return err; 14663d0407baSopenharmony_ci} 14673d0407baSopenharmony_ci 14683d0407baSopenharmony_cistatic void l2cap_sock_cleanup_listen(struct sock *parent) 14693d0407baSopenharmony_ci{ 14703d0407baSopenharmony_ci struct sock *sk; 14713d0407baSopenharmony_ci 14723d0407baSopenharmony_ci BT_DBG("parent %p state %s", parent, state_to_string(parent->sk_state)); 14733d0407baSopenharmony_ci 14743d0407baSopenharmony_ci /* Close not yet accepted channels */ 14753d0407baSopenharmony_ci while ((sk = bt_accept_dequeue(parent, NULL))) { 14763d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 14773d0407baSopenharmony_ci 14783d0407baSopenharmony_ci BT_DBG("child chan %p state %s", chan, state_to_string(chan->state)); 14793d0407baSopenharmony_ci 14803d0407baSopenharmony_ci l2cap_chan_hold(chan); 14813d0407baSopenharmony_ci l2cap_chan_lock(chan); 14823d0407baSopenharmony_ci 14833d0407baSopenharmony_ci __clear_chan_timer(chan); 14843d0407baSopenharmony_ci l2cap_chan_close(chan, ECONNRESET); 14853d0407baSopenharmony_ci l2cap_sock_kill(sk); 14863d0407baSopenharmony_ci 14873d0407baSopenharmony_ci l2cap_chan_unlock(chan); 14883d0407baSopenharmony_ci l2cap_chan_put(chan); 14893d0407baSopenharmony_ci } 14903d0407baSopenharmony_ci} 14913d0407baSopenharmony_ci 14923d0407baSopenharmony_cistatic struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan) 14933d0407baSopenharmony_ci{ 14943d0407baSopenharmony_ci struct sock *sk, *parent = chan->data; 14953d0407baSopenharmony_ci 14963d0407baSopenharmony_ci lock_sock(parent); 14973d0407baSopenharmony_ci 14983d0407baSopenharmony_ci /* Check for backlog size */ 14993d0407baSopenharmony_ci if (sk_acceptq_is_full(parent)) { 15003d0407baSopenharmony_ci BT_DBG("backlog full %d", parent->sk_ack_backlog); 15013d0407baSopenharmony_ci release_sock(parent); 15023d0407baSopenharmony_ci return NULL; 15033d0407baSopenharmony_ci } 15043d0407baSopenharmony_ci 15053d0407baSopenharmony_ci sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC, 0); 15063d0407baSopenharmony_ci if (!sk) { 15073d0407baSopenharmony_ci release_sock(parent); 15083d0407baSopenharmony_ci return NULL; 15093d0407baSopenharmony_ci } 15103d0407baSopenharmony_ci 15113d0407baSopenharmony_ci bt_sock_reclassify_lock(sk, BTPROTO_L2CAP); 15123d0407baSopenharmony_ci 15133d0407baSopenharmony_ci l2cap_sock_init(sk, parent); 15143d0407baSopenharmony_ci 15153d0407baSopenharmony_ci bt_accept_enqueue(parent, sk, false); 15163d0407baSopenharmony_ci 15173d0407baSopenharmony_ci release_sock(parent); 15183d0407baSopenharmony_ci 15193d0407baSopenharmony_ci return l2cap_pi(sk)->chan; 15203d0407baSopenharmony_ci} 15213d0407baSopenharmony_ci 15223d0407baSopenharmony_cistatic int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) 15233d0407baSopenharmony_ci{ 15243d0407baSopenharmony_ci struct sock *sk = chan->data; 15253d0407baSopenharmony_ci int err; 15263d0407baSopenharmony_ci 15273d0407baSopenharmony_ci lock_sock(sk); 15283d0407baSopenharmony_ci 15293d0407baSopenharmony_ci if (l2cap_pi(sk)->rx_busy_skb) { 15303d0407baSopenharmony_ci err = -ENOMEM; 15313d0407baSopenharmony_ci goto done; 15323d0407baSopenharmony_ci } 15333d0407baSopenharmony_ci 15343d0407baSopenharmony_ci if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING) { 15353d0407baSopenharmony_ci /* Even if no filter is attached, we could potentially 15363d0407baSopenharmony_ci * get errors from security modules, etc. 15373d0407baSopenharmony_ci */ 15383d0407baSopenharmony_ci err = sk_filter(sk, skb); 15393d0407baSopenharmony_ci if (err) { 15403d0407baSopenharmony_ci goto done; 15413d0407baSopenharmony_ci } 15423d0407baSopenharmony_ci } 15433d0407baSopenharmony_ci 15443d0407baSopenharmony_ci err = __sock_queue_rcv_skb(sk, skb); 15453d0407baSopenharmony_ci /* For ERTM, handle one skb that doesn't fit into the recv 15463d0407baSopenharmony_ci * buffer. This is important to do because the data frames 15473d0407baSopenharmony_ci * have already been acked, so the skb cannot be discarded. 15483d0407baSopenharmony_ci * 15493d0407baSopenharmony_ci * Notify the l2cap core that the buffer is full, so the 15503d0407baSopenharmony_ci * LOCAL_BUSY state is entered and no more frames are 15513d0407baSopenharmony_ci * acked and reassembled until there is buffer space 15523d0407baSopenharmony_ci * available. 15533d0407baSopenharmony_ci */ 15543d0407baSopenharmony_ci if (err < 0 && chan->mode == L2CAP_MODE_ERTM) { 15553d0407baSopenharmony_ci l2cap_pi(sk)->rx_busy_skb = skb; 15563d0407baSopenharmony_ci l2cap_chan_busy(chan, 1); 15573d0407baSopenharmony_ci err = 0; 15583d0407baSopenharmony_ci } 15593d0407baSopenharmony_ci 15603d0407baSopenharmony_cidone: 15613d0407baSopenharmony_ci release_sock(sk); 15623d0407baSopenharmony_ci 15633d0407baSopenharmony_ci return err; 15643d0407baSopenharmony_ci} 15653d0407baSopenharmony_ci 15663d0407baSopenharmony_cistatic void l2cap_sock_close_cb(struct l2cap_chan *chan) 15673d0407baSopenharmony_ci{ 15683d0407baSopenharmony_ci struct sock *sk = chan->data; 15693d0407baSopenharmony_ci 15703d0407baSopenharmony_ci l2cap_sock_kill(sk); 15713d0407baSopenharmony_ci} 15723d0407baSopenharmony_ci 15733d0407baSopenharmony_cistatic void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err) 15743d0407baSopenharmony_ci{ 15753d0407baSopenharmony_ci struct sock *sk = chan->data; 15763d0407baSopenharmony_ci struct sock *parent; 15773d0407baSopenharmony_ci 15783d0407baSopenharmony_ci BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); 15793d0407baSopenharmony_ci 15803d0407baSopenharmony_ci /* This callback can be called both for server (BT_LISTEN) 15813d0407baSopenharmony_ci * sockets as well as "normal" ones. To avoid lockdep warnings 15823d0407baSopenharmony_ci * with child socket locking (through l2cap_sock_cleanup_listen) 15833d0407baSopenharmony_ci * we need separation into separate nesting levels. The simplest 15843d0407baSopenharmony_ci * way to accomplish this is to inherit the nesting level used 15853d0407baSopenharmony_ci * for the channel. 15863d0407baSopenharmony_ci */ 15873d0407baSopenharmony_ci lock_sock_nested(sk, atomic_read(&chan->nesting)); 15883d0407baSopenharmony_ci 15893d0407baSopenharmony_ci parent = bt_sk(sk)->parent; 15903d0407baSopenharmony_ci 15913d0407baSopenharmony_ci switch (chan->state) { 15923d0407baSopenharmony_ci case BT_OPEN: 15933d0407baSopenharmony_ci case BT_BOUND: 15943d0407baSopenharmony_ci case BT_CLOSED: 15953d0407baSopenharmony_ci break; 15963d0407baSopenharmony_ci case BT_LISTEN: 15973d0407baSopenharmony_ci l2cap_sock_cleanup_listen(sk); 15983d0407baSopenharmony_ci sk->sk_state = BT_CLOSED; 15993d0407baSopenharmony_ci chan->state = BT_CLOSED; 16003d0407baSopenharmony_ci 16013d0407baSopenharmony_ci break; 16023d0407baSopenharmony_ci default: 16033d0407baSopenharmony_ci sk->sk_state = BT_CLOSED; 16043d0407baSopenharmony_ci chan->state = BT_CLOSED; 16053d0407baSopenharmony_ci 16063d0407baSopenharmony_ci sk->sk_err = err; 16073d0407baSopenharmony_ci 16083d0407baSopenharmony_ci if (parent) { 16093d0407baSopenharmony_ci bt_accept_unlink(sk); 16103d0407baSopenharmony_ci parent->sk_data_ready(parent); 16113d0407baSopenharmony_ci } else { 16123d0407baSopenharmony_ci sk->sk_state_change(sk); 16133d0407baSopenharmony_ci } 16143d0407baSopenharmony_ci 16153d0407baSopenharmony_ci break; 16163d0407baSopenharmony_ci } 16173d0407baSopenharmony_ci release_sock(sk); 16183d0407baSopenharmony_ci 16193d0407baSopenharmony_ci /* Only zap after cleanup to avoid use after free race */ 16203d0407baSopenharmony_ci sock_set_flag(sk, SOCK_ZAPPED); 16213d0407baSopenharmony_ci} 16223d0407baSopenharmony_ci 16233d0407baSopenharmony_cistatic void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state, int err) 16243d0407baSopenharmony_ci{ 16253d0407baSopenharmony_ci struct sock *sk = chan->data; 16263d0407baSopenharmony_ci 16273d0407baSopenharmony_ci sk->sk_state = state; 16283d0407baSopenharmony_ci 16293d0407baSopenharmony_ci if (err) { 16303d0407baSopenharmony_ci sk->sk_err = err; 16313d0407baSopenharmony_ci } 16323d0407baSopenharmony_ci} 16333d0407baSopenharmony_ci 16343d0407baSopenharmony_cistatic struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, unsigned long hdr_len, unsigned long len, 16353d0407baSopenharmony_ci int nb) 16363d0407baSopenharmony_ci{ 16373d0407baSopenharmony_ci struct sock *sk = chan->data; 16383d0407baSopenharmony_ci struct sk_buff *skb; 16393d0407baSopenharmony_ci int err; 16403d0407baSopenharmony_ci 16413d0407baSopenharmony_ci l2cap_chan_unlock(chan); 16423d0407baSopenharmony_ci skb = bt_skb_send_alloc(sk, hdr_len + len, nb, &err); 16433d0407baSopenharmony_ci l2cap_chan_lock(chan); 16443d0407baSopenharmony_ci 16453d0407baSopenharmony_ci if (!skb) { 16463d0407baSopenharmony_ci return ERR_PTR(err); 16473d0407baSopenharmony_ci } 16483d0407baSopenharmony_ci 16493d0407baSopenharmony_ci skb->priority = sk->sk_priority; 16503d0407baSopenharmony_ci 16513d0407baSopenharmony_ci bt_cb(skb)->l2cap.chan = chan; 16523d0407baSopenharmony_ci 16533d0407baSopenharmony_ci return skb; 16543d0407baSopenharmony_ci} 16553d0407baSopenharmony_ci 16563d0407baSopenharmony_cistatic void l2cap_sock_ready_cb(struct l2cap_chan *chan) 16573d0407baSopenharmony_ci{ 16583d0407baSopenharmony_ci struct sock *sk = chan->data; 16593d0407baSopenharmony_ci struct sock *parent; 16603d0407baSopenharmony_ci 16613d0407baSopenharmony_ci lock_sock(sk); 16623d0407baSopenharmony_ci 16633d0407baSopenharmony_ci parent = bt_sk(sk)->parent; 16643d0407baSopenharmony_ci 16653d0407baSopenharmony_ci BT_DBG("sk %p, parent %p", sk, parent); 16663d0407baSopenharmony_ci 16673d0407baSopenharmony_ci sk->sk_state = BT_CONNECTED; 16683d0407baSopenharmony_ci sk->sk_state_change(sk); 16693d0407baSopenharmony_ci 16703d0407baSopenharmony_ci if (parent) { 16713d0407baSopenharmony_ci parent->sk_data_ready(parent); 16723d0407baSopenharmony_ci } 16733d0407baSopenharmony_ci 16743d0407baSopenharmony_ci release_sock(sk); 16753d0407baSopenharmony_ci} 16763d0407baSopenharmony_ci 16773d0407baSopenharmony_cistatic void l2cap_sock_defer_cb(struct l2cap_chan *chan) 16783d0407baSopenharmony_ci{ 16793d0407baSopenharmony_ci struct sock *parent, *sk = chan->data; 16803d0407baSopenharmony_ci 16813d0407baSopenharmony_ci lock_sock(sk); 16823d0407baSopenharmony_ci 16833d0407baSopenharmony_ci parent = bt_sk(sk)->parent; 16843d0407baSopenharmony_ci if (parent) { 16853d0407baSopenharmony_ci parent->sk_data_ready(parent); 16863d0407baSopenharmony_ci } 16873d0407baSopenharmony_ci 16883d0407baSopenharmony_ci release_sock(sk); 16893d0407baSopenharmony_ci} 16903d0407baSopenharmony_ci 16913d0407baSopenharmony_cistatic void l2cap_sock_resume_cb(struct l2cap_chan *chan) 16923d0407baSopenharmony_ci{ 16933d0407baSopenharmony_ci struct sock *sk = chan->data; 16943d0407baSopenharmony_ci 16953d0407baSopenharmony_ci if (test_and_clear_bit(FLAG_PENDING_SECURITY, &chan->flags)) { 16963d0407baSopenharmony_ci sk->sk_state = BT_CONNECTED; 16973d0407baSopenharmony_ci chan->state = BT_CONNECTED; 16983d0407baSopenharmony_ci } 16993d0407baSopenharmony_ci 17003d0407baSopenharmony_ci clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); 17013d0407baSopenharmony_ci sk->sk_state_change(sk); 17023d0407baSopenharmony_ci} 17033d0407baSopenharmony_ci 17043d0407baSopenharmony_cistatic void l2cap_sock_set_shutdown_cb(struct l2cap_chan *chan) 17053d0407baSopenharmony_ci{ 17063d0407baSopenharmony_ci struct sock *sk = chan->data; 17073d0407baSopenharmony_ci 17083d0407baSopenharmony_ci lock_sock(sk); 17093d0407baSopenharmony_ci sk->sk_shutdown = SHUTDOWN_MASK; 17103d0407baSopenharmony_ci release_sock(sk); 17113d0407baSopenharmony_ci} 17123d0407baSopenharmony_ci 17133d0407baSopenharmony_cistatic long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan) 17143d0407baSopenharmony_ci{ 17153d0407baSopenharmony_ci struct sock *sk = chan->data; 17163d0407baSopenharmony_ci 17173d0407baSopenharmony_ci return sk->sk_sndtimeo; 17183d0407baSopenharmony_ci} 17193d0407baSopenharmony_ci 17203d0407baSopenharmony_cistatic struct pid *l2cap_sock_get_peer_pid_cb(struct l2cap_chan *chan) 17213d0407baSopenharmony_ci{ 17223d0407baSopenharmony_ci struct sock *sk = chan->data; 17233d0407baSopenharmony_ci 17243d0407baSopenharmony_ci return sk->sk_peer_pid; 17253d0407baSopenharmony_ci} 17263d0407baSopenharmony_ci 17273d0407baSopenharmony_cistatic void l2cap_sock_suspend_cb(struct l2cap_chan *chan) 17283d0407baSopenharmony_ci{ 17293d0407baSopenharmony_ci struct sock *sk = chan->data; 17303d0407baSopenharmony_ci 17313d0407baSopenharmony_ci set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); 17323d0407baSopenharmony_ci sk->sk_state_change(sk); 17333d0407baSopenharmony_ci} 17343d0407baSopenharmony_ci 17353d0407baSopenharmony_cistatic int l2cap_sock_filter(struct l2cap_chan *chan, struct sk_buff *skb) 17363d0407baSopenharmony_ci{ 17373d0407baSopenharmony_ci struct sock *sk = chan->data; 17383d0407baSopenharmony_ci if ((chan->mode == L2CAP_MODE_ERTM) || (chan->mode == L2CAP_MODE_STREAMING)) { 17393d0407baSopenharmony_ci return sk_filter(sk, skb); 17403d0407baSopenharmony_ci } 17413d0407baSopenharmony_ci return 0; 17423d0407baSopenharmony_ci} 17433d0407baSopenharmony_ci 17443d0407baSopenharmony_cistatic const struct l2cap_ops l2cap_chan_ops = { 17453d0407baSopenharmony_ci .name = "L2CAP Socket Interface", 17463d0407baSopenharmony_ci .new_connection = l2cap_sock_new_connection_cb, 17473d0407baSopenharmony_ci .recv = l2cap_sock_recv_cb, 17483d0407baSopenharmony_ci .close = l2cap_sock_close_cb, 17493d0407baSopenharmony_ci .teardown = l2cap_sock_teardown_cb, 17503d0407baSopenharmony_ci .state_change = l2cap_sock_state_change_cb, 17513d0407baSopenharmony_ci .ready = l2cap_sock_ready_cb, 17523d0407baSopenharmony_ci .defer = l2cap_sock_defer_cb, 17533d0407baSopenharmony_ci .resume = l2cap_sock_resume_cb, 17543d0407baSopenharmony_ci .suspend = l2cap_sock_suspend_cb, 17553d0407baSopenharmony_ci .set_shutdown = l2cap_sock_set_shutdown_cb, 17563d0407baSopenharmony_ci .get_sndtimeo = l2cap_sock_get_sndtimeo_cb, 17573d0407baSopenharmony_ci .get_peer_pid = l2cap_sock_get_peer_pid_cb, 17583d0407baSopenharmony_ci .alloc_skb = l2cap_sock_alloc_skb_cb, 17593d0407baSopenharmony_ci .filter = l2cap_sock_filter, 17603d0407baSopenharmony_ci}; 17613d0407baSopenharmony_ci 17623d0407baSopenharmony_cistatic void l2cap_sock_destruct(struct sock *sk) 17633d0407baSopenharmony_ci{ 17643d0407baSopenharmony_ci BT_DBG("sk %p", sk); 17653d0407baSopenharmony_ci 17663d0407baSopenharmony_ci if (l2cap_pi(sk)->chan) { 17673d0407baSopenharmony_ci l2cap_chan_put(l2cap_pi(sk)->chan); 17683d0407baSopenharmony_ci } 17693d0407baSopenharmony_ci 17703d0407baSopenharmony_ci if (l2cap_pi(sk)->rx_busy_skb) { 17713d0407baSopenharmony_ci kfree_skb(l2cap_pi(sk)->rx_busy_skb); 17723d0407baSopenharmony_ci l2cap_pi(sk)->rx_busy_skb = NULL; 17733d0407baSopenharmony_ci } 17743d0407baSopenharmony_ci 17753d0407baSopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 17763d0407baSopenharmony_ci skb_queue_purge(&sk->sk_write_queue); 17773d0407baSopenharmony_ci} 17783d0407baSopenharmony_ci 17793d0407baSopenharmony_cistatic void l2cap_skb_msg_name(struct sk_buff *skb, void *msg_name, int *msg_namelen) 17803d0407baSopenharmony_ci{ 17813d0407baSopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_l2 *, la, msg_name); 17823d0407baSopenharmony_ci 17833d0407baSopenharmony_ci memset(la, 0, sizeof(struct sockaddr_l2)); 17843d0407baSopenharmony_ci la->l2_family = AF_BLUETOOTH; 17853d0407baSopenharmony_ci la->l2_psm = bt_cb(skb)->l2cap.psm; 17863d0407baSopenharmony_ci bacpy(&la->l2_bdaddr, &bt_cb(skb)->l2cap.bdaddr); 17873d0407baSopenharmony_ci 17883d0407baSopenharmony_ci *msg_namelen = sizeof(struct sockaddr_l2); 17893d0407baSopenharmony_ci} 17903d0407baSopenharmony_ci 17913d0407baSopenharmony_cistatic void l2cap_sock_init(struct sock *sk, struct sock *parent) 17923d0407baSopenharmony_ci{ 17933d0407baSopenharmony_ci struct l2cap_chan *chan = l2cap_pi(sk)->chan; 17943d0407baSopenharmony_ci 17953d0407baSopenharmony_ci BT_DBG("sk %p", sk); 17963d0407baSopenharmony_ci 17973d0407baSopenharmony_ci if (parent) { 17983d0407baSopenharmony_ci struct l2cap_chan *pchan = l2cap_pi(parent)->chan; 17993d0407baSopenharmony_ci 18003d0407baSopenharmony_ci sk->sk_type = parent->sk_type; 18013d0407baSopenharmony_ci bt_sk(sk)->flags = bt_sk(parent)->flags; 18023d0407baSopenharmony_ci 18033d0407baSopenharmony_ci chan->chan_type = pchan->chan_type; 18043d0407baSopenharmony_ci chan->imtu = pchan->imtu; 18053d0407baSopenharmony_ci chan->omtu = pchan->omtu; 18063d0407baSopenharmony_ci chan->conf_state = pchan->conf_state; 18073d0407baSopenharmony_ci chan->mode = pchan->mode; 18083d0407baSopenharmony_ci chan->fcs = pchan->fcs; 18093d0407baSopenharmony_ci chan->max_tx = pchan->max_tx; 18103d0407baSopenharmony_ci chan->tx_win = pchan->tx_win; 18113d0407baSopenharmony_ci chan->tx_win_max = pchan->tx_win_max; 18123d0407baSopenharmony_ci chan->sec_level = pchan->sec_level; 18133d0407baSopenharmony_ci chan->flags = pchan->flags; 18143d0407baSopenharmony_ci chan->tx_credits = pchan->tx_credits; 18153d0407baSopenharmony_ci chan->rx_credits = pchan->rx_credits; 18163d0407baSopenharmony_ci 18173d0407baSopenharmony_ci if (chan->chan_type == L2CAP_CHAN_FIXED) { 18183d0407baSopenharmony_ci chan->scid = pchan->scid; 18193d0407baSopenharmony_ci chan->dcid = pchan->scid; 18203d0407baSopenharmony_ci } 18213d0407baSopenharmony_ci 18223d0407baSopenharmony_ci security_sk_clone(parent, sk); 18233d0407baSopenharmony_ci } else { 18243d0407baSopenharmony_ci switch (sk->sk_type) { 18253d0407baSopenharmony_ci case SOCK_RAW: 18263d0407baSopenharmony_ci chan->chan_type = L2CAP_CHAN_RAW; 18273d0407baSopenharmony_ci break; 18283d0407baSopenharmony_ci case SOCK_DGRAM: 18293d0407baSopenharmony_ci chan->chan_type = L2CAP_CHAN_CONN_LESS; 18303d0407baSopenharmony_ci bt_sk(sk)->skb_msg_name = l2cap_skb_msg_name; 18313d0407baSopenharmony_ci break; 18323d0407baSopenharmony_ci case SOCK_SEQPACKET: 18333d0407baSopenharmony_ci case SOCK_STREAM: 18343d0407baSopenharmony_ci chan->chan_type = L2CAP_CHAN_CONN_ORIENTED; 18353d0407baSopenharmony_ci break; 18363d0407baSopenharmony_ci } 18373d0407baSopenharmony_ci 18383d0407baSopenharmony_ci chan->imtu = L2CAP_DEFAULT_MTU; 18393d0407baSopenharmony_ci chan->omtu = 0; 18403d0407baSopenharmony_ci if (!disable_ertm && sk->sk_type == SOCK_STREAM) { 18413d0407baSopenharmony_ci chan->mode = L2CAP_MODE_ERTM; 18423d0407baSopenharmony_ci set_bit(CONF_STATE2_DEVICE, &chan->conf_state); 18433d0407baSopenharmony_ci } else { 18443d0407baSopenharmony_ci chan->mode = L2CAP_MODE_BASIC; 18453d0407baSopenharmony_ci } 18463d0407baSopenharmony_ci 18473d0407baSopenharmony_ci l2cap_chan_set_defaults(chan); 18483d0407baSopenharmony_ci } 18493d0407baSopenharmony_ci 18503d0407baSopenharmony_ci /* Default config options */ 18513d0407baSopenharmony_ci chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; 18523d0407baSopenharmony_ci 18533d0407baSopenharmony_ci chan->data = sk; 18543d0407baSopenharmony_ci chan->ops = &l2cap_chan_ops; 18553d0407baSopenharmony_ci} 18563d0407baSopenharmony_ci 18573d0407baSopenharmony_cistatic struct proto l2cap_proto = {.name = "L2CAP", .owner = THIS_MODULE, .obj_size = sizeof(struct l2cap_pinfo)}; 18583d0407baSopenharmony_ci 18593d0407baSopenharmony_cistatic struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio, int kern) 18603d0407baSopenharmony_ci{ 18613d0407baSopenharmony_ci struct sock *sk; 18623d0407baSopenharmony_ci struct l2cap_chan *chan; 18633d0407baSopenharmony_ci 18643d0407baSopenharmony_ci sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto, kern); 18653d0407baSopenharmony_ci if (!sk) { 18663d0407baSopenharmony_ci return NULL; 18673d0407baSopenharmony_ci } 18683d0407baSopenharmony_ci 18693d0407baSopenharmony_ci sock_init_data(sock, sk); 18703d0407baSopenharmony_ci INIT_LIST_HEAD(&bt_sk(sk)->accept_q); 18713d0407baSopenharmony_ci 18723d0407baSopenharmony_ci sk->sk_destruct = l2cap_sock_destruct; 18733d0407baSopenharmony_ci sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; 18743d0407baSopenharmony_ci 18753d0407baSopenharmony_ci sock_reset_flag(sk, SOCK_ZAPPED); 18763d0407baSopenharmony_ci 18773d0407baSopenharmony_ci sk->sk_protocol = proto; 18783d0407baSopenharmony_ci sk->sk_state = BT_OPEN; 18793d0407baSopenharmony_ci 18803d0407baSopenharmony_ci chan = l2cap_chan_create(); 18813d0407baSopenharmony_ci if (!chan) { 18823d0407baSopenharmony_ci sk_free(sk); 18833d0407baSopenharmony_ci return NULL; 18843d0407baSopenharmony_ci } 18853d0407baSopenharmony_ci 18863d0407baSopenharmony_ci l2cap_chan_hold(chan); 18873d0407baSopenharmony_ci 18883d0407baSopenharmony_ci l2cap_pi(sk)->chan = chan; 18893d0407baSopenharmony_ci 18903d0407baSopenharmony_ci return sk; 18913d0407baSopenharmony_ci} 18923d0407baSopenharmony_ci 18933d0407baSopenharmony_cistatic int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, int kern) 18943d0407baSopenharmony_ci{ 18953d0407baSopenharmony_ci struct sock *sk; 18963d0407baSopenharmony_ci 18973d0407baSopenharmony_ci BT_DBG("sock %p", sock); 18983d0407baSopenharmony_ci 18993d0407baSopenharmony_ci sock->state = SS_UNCONNECTED; 19003d0407baSopenharmony_ci 19013d0407baSopenharmony_ci if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM && 19023d0407baSopenharmony_ci sock->type != SOCK_RAW) { 19033d0407baSopenharmony_ci return -ESOCKTNOSUPPORT; 19043d0407baSopenharmony_ci } 19053d0407baSopenharmony_ci 19063d0407baSopenharmony_ci if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) { 19073d0407baSopenharmony_ci return -EPERM; 19083d0407baSopenharmony_ci } 19093d0407baSopenharmony_ci 19103d0407baSopenharmony_ci sock->ops = &l2cap_sock_ops; 19113d0407baSopenharmony_ci 19123d0407baSopenharmony_ci sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern); 19133d0407baSopenharmony_ci if (!sk) { 19143d0407baSopenharmony_ci return -ENOMEM; 19153d0407baSopenharmony_ci } 19163d0407baSopenharmony_ci 19173d0407baSopenharmony_ci l2cap_sock_init(sk, NULL); 19183d0407baSopenharmony_ci bt_sock_link(&l2cap_sk_list, sk); 19193d0407baSopenharmony_ci return 0; 19203d0407baSopenharmony_ci} 19213d0407baSopenharmony_ci 19223d0407baSopenharmony_cistatic const struct proto_ops l2cap_sock_ops = {.family = PF_BLUETOOTH, 19233d0407baSopenharmony_ci .owner = THIS_MODULE, 19243d0407baSopenharmony_ci .release = l2cap_sock_release, 19253d0407baSopenharmony_ci .bind = l2cap_sock_bind, 19263d0407baSopenharmony_ci .connect = l2cap_sock_connect, 19273d0407baSopenharmony_ci .listen = l2cap_sock_listen, 19283d0407baSopenharmony_ci .accept = l2cap_sock_accept, 19293d0407baSopenharmony_ci .getname = l2cap_sock_getname, 19303d0407baSopenharmony_ci .sendmsg = l2cap_sock_sendmsg, 19313d0407baSopenharmony_ci .recvmsg = l2cap_sock_recvmsg, 19323d0407baSopenharmony_ci .poll = bt_sock_poll, 19333d0407baSopenharmony_ci .ioctl = bt_sock_ioctl, 19343d0407baSopenharmony_ci .gettstamp = sock_gettstamp, 19353d0407baSopenharmony_ci .mmap = sock_no_mmap, 19363d0407baSopenharmony_ci .socketpair = sock_no_socketpair, 19373d0407baSopenharmony_ci .shutdown = l2cap_sock_shutdown, 19383d0407baSopenharmony_ci .setsockopt = l2cap_sock_setsockopt, 19393d0407baSopenharmony_ci .getsockopt = l2cap_sock_getsockopt}; 19403d0407baSopenharmony_ci 19413d0407baSopenharmony_cistatic const struct net_proto_family l2cap_sock_family_ops = { 19423d0407baSopenharmony_ci .family = PF_BLUETOOTH, 19433d0407baSopenharmony_ci .owner = THIS_MODULE, 19443d0407baSopenharmony_ci .create = l2cap_sock_create, 19453d0407baSopenharmony_ci}; 19463d0407baSopenharmony_ci 19473d0407baSopenharmony_ciint __init l2cap_init_sockets(void) 19483d0407baSopenharmony_ci{ 19493d0407baSopenharmony_ci int err; 19503d0407baSopenharmony_ci 19513d0407baSopenharmony_ci BUILD_BUG_ON(sizeof(struct sockaddr_l2) > sizeof(struct sockaddr)); 19523d0407baSopenharmony_ci 19533d0407baSopenharmony_ci err = proto_register(&l2cap_proto, 0); 19543d0407baSopenharmony_ci if (err < 0) { 19553d0407baSopenharmony_ci return err; 19563d0407baSopenharmony_ci } 19573d0407baSopenharmony_ci 19583d0407baSopenharmony_ci err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops); 19593d0407baSopenharmony_ci if (err < 0) { 19603d0407baSopenharmony_ci BT_ERR("L2CAP socket registration failed"); 19613d0407baSopenharmony_ci goto error; 19623d0407baSopenharmony_ci } 19633d0407baSopenharmony_ci 19643d0407baSopenharmony_ci err = bt_procfs_init(&init_net, "l2cap", &l2cap_sk_list, NULL); 19653d0407baSopenharmony_ci if (err < 0) { 19663d0407baSopenharmony_ci BT_ERR("Failed to create L2CAP proc file"); 19673d0407baSopenharmony_ci bt_sock_unregister(BTPROTO_L2CAP); 19683d0407baSopenharmony_ci goto error; 19693d0407baSopenharmony_ci } 19703d0407baSopenharmony_ci 19713d0407baSopenharmony_ci BT_INFO("L2CAP socket layer initialized"); 19723d0407baSopenharmony_ci 19733d0407baSopenharmony_ci return 0; 19743d0407baSopenharmony_ci 19753d0407baSopenharmony_cierror: 19763d0407baSopenharmony_ci proto_unregister(&l2cap_proto); 19773d0407baSopenharmony_ci return err; 19783d0407baSopenharmony_ci} 19793d0407baSopenharmony_ci 19803d0407baSopenharmony_civoid l2cap_cleanup_sockets(void) 19813d0407baSopenharmony_ci{ 19823d0407baSopenharmony_ci bt_procfs_cleanup(&init_net, "l2cap"); 19833d0407baSopenharmony_ci bt_sock_unregister(BTPROTO_L2CAP); 19843d0407baSopenharmony_ci proto_unregister(&l2cap_proto); 19853d0407baSopenharmony_ci} 1986