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