18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci   BlueZ - Bluetooth protocol stack for Linux
38c2ecf20Sopenharmony_ci   Copyright (C) 2000-2001 Qualcomm Incorporated
48c2ecf20Sopenharmony_ci   Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
58c2ecf20Sopenharmony_ci   Copyright (C) 2010 Google Inc.
68c2ecf20Sopenharmony_ci   Copyright (C) 2011 ProFUSION Embedded Systems
78c2ecf20Sopenharmony_ci   Copyright (c) 2012 Code Aurora Forum.  All rights reserved.
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci   This program is free software; you can redistribute it and/or modify
128c2ecf20Sopenharmony_ci   it under the terms of the GNU General Public License version 2 as
138c2ecf20Sopenharmony_ci   published by the Free Software Foundation;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
168c2ecf20Sopenharmony_ci   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178c2ecf20Sopenharmony_ci   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
188c2ecf20Sopenharmony_ci   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
198c2ecf20Sopenharmony_ci   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
208c2ecf20Sopenharmony_ci   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
218c2ecf20Sopenharmony_ci   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
228c2ecf20Sopenharmony_ci   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
258c2ecf20Sopenharmony_ci   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
268c2ecf20Sopenharmony_ci   SOFTWARE IS DISCLAIMED.
278c2ecf20Sopenharmony_ci*/
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* Bluetooth L2CAP core. */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include <linux/module.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
348c2ecf20Sopenharmony_ci#include <linux/crc16.h>
358c2ecf20Sopenharmony_ci#include <linux/filter.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
388c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h>
398c2ecf20Sopenharmony_ci#include <net/bluetooth/l2cap.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include "smp.h"
428c2ecf20Sopenharmony_ci#include "a2mp.h"
438c2ecf20Sopenharmony_ci#include "amp.h"
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define LE_FLOWCTL_MAX_CREDITS 65535
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cibool disable_ertm;
488c2ecf20Sopenharmony_cibool enable_ecred;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN | L2CAP_FEAT_UCD;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic LIST_HEAD(chan_list);
538c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(chan_list_lock);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
568c2ecf20Sopenharmony_ci				       u8 code, u8 ident, u16 dlen, void *data);
578c2ecf20Sopenharmony_cistatic void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
588c2ecf20Sopenharmony_ci			   void *data);
598c2ecf20Sopenharmony_cistatic int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size);
608c2ecf20Sopenharmony_cistatic void l2cap_send_disconn_req(struct l2cap_chan *chan, int err);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
638c2ecf20Sopenharmony_ci		     struct sk_buff_head *skbs, u8 event);
648c2ecf20Sopenharmony_cistatic void l2cap_retrans_timeout(struct work_struct *work);
658c2ecf20Sopenharmony_cistatic void l2cap_monitor_timeout(struct work_struct *work);
668c2ecf20Sopenharmony_cistatic void l2cap_ack_timeout(struct work_struct *work);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic inline u8 bdaddr_type(u8 link_type, u8 bdaddr_type)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	if (link_type == LE_LINK) {
718c2ecf20Sopenharmony_ci		if (bdaddr_type == ADDR_LE_DEV_PUBLIC)
728c2ecf20Sopenharmony_ci			return BDADDR_LE_PUBLIC;
738c2ecf20Sopenharmony_ci		else
748c2ecf20Sopenharmony_ci			return BDADDR_LE_RANDOM;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return BDADDR_BREDR;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic inline u8 bdaddr_src_type(struct hci_conn *hcon)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	return bdaddr_type(hcon->type, hcon->src_type);
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic inline u8 bdaddr_dst_type(struct hci_conn *hcon)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	return bdaddr_type(hcon->type, hcon->dst_type);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/* ---- L2CAP channels ---- */
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
938c2ecf20Sopenharmony_ci						   u16 cid)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct l2cap_chan *c;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	list_for_each_entry(c, &conn->chan_l, list) {
988c2ecf20Sopenharmony_ci		if (c->dcid == cid)
998c2ecf20Sopenharmony_ci			return c;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci	return NULL;
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn,
1058c2ecf20Sopenharmony_ci						   u16 cid)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	struct l2cap_chan *c;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	list_for_each_entry(c, &conn->chan_l, list) {
1108c2ecf20Sopenharmony_ci		if (c->scid == cid)
1118c2ecf20Sopenharmony_ci			return c;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci	return NULL;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci/* Find channel with given SCID.
1178c2ecf20Sopenharmony_ci * Returns a reference locked channel.
1188c2ecf20Sopenharmony_ci */
1198c2ecf20Sopenharmony_cistatic struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,
1208c2ecf20Sopenharmony_ci						 u16 cid)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	struct l2cap_chan *c;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
1258c2ecf20Sopenharmony_ci	c = __l2cap_get_chan_by_scid(conn, cid);
1268c2ecf20Sopenharmony_ci	if (c) {
1278c2ecf20Sopenharmony_ci		/* Only lock if chan reference is not 0 */
1288c2ecf20Sopenharmony_ci		c = l2cap_chan_hold_unless_zero(c);
1298c2ecf20Sopenharmony_ci		if (c)
1308c2ecf20Sopenharmony_ci			l2cap_chan_lock(c);
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return c;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* Find channel with given DCID.
1388c2ecf20Sopenharmony_ci * Returns a reference locked channel.
1398c2ecf20Sopenharmony_ci */
1408c2ecf20Sopenharmony_cistatic struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
1418c2ecf20Sopenharmony_ci						 u16 cid)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct l2cap_chan *c;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
1468c2ecf20Sopenharmony_ci	c = __l2cap_get_chan_by_dcid(conn, cid);
1478c2ecf20Sopenharmony_ci	if (c) {
1488c2ecf20Sopenharmony_ci		/* Only lock if chan reference is not 0 */
1498c2ecf20Sopenharmony_ci		c = l2cap_chan_hold_unless_zero(c);
1508c2ecf20Sopenharmony_ci		if (c)
1518c2ecf20Sopenharmony_ci			l2cap_chan_lock(c);
1528c2ecf20Sopenharmony_ci	}
1538c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return c;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,
1598c2ecf20Sopenharmony_ci						    u8 ident)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct l2cap_chan *c;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	list_for_each_entry(c, &conn->chan_l, list) {
1648c2ecf20Sopenharmony_ci		if (c->ident == ident)
1658c2ecf20Sopenharmony_ci			return c;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci	return NULL;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn,
1718c2ecf20Sopenharmony_ci						  u8 ident)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	struct l2cap_chan *c;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
1768c2ecf20Sopenharmony_ci	c = __l2cap_get_chan_by_ident(conn, ident);
1778c2ecf20Sopenharmony_ci	if (c) {
1788c2ecf20Sopenharmony_ci		/* Only lock if chan reference is not 0 */
1798c2ecf20Sopenharmony_ci		c = l2cap_chan_hold_unless_zero(c);
1808c2ecf20Sopenharmony_ci		if (c)
1818c2ecf20Sopenharmony_ci			l2cap_chan_lock(c);
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return c;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src,
1898c2ecf20Sopenharmony_ci						      u8 src_type)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct l2cap_chan *c;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	list_for_each_entry(c, &chan_list, global_l) {
1948c2ecf20Sopenharmony_ci		if (src_type == BDADDR_BREDR && c->src_type != BDADDR_BREDR)
1958c2ecf20Sopenharmony_ci			continue;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		if (src_type != BDADDR_BREDR && c->src_type == BDADDR_BREDR)
1988c2ecf20Sopenharmony_ci			continue;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		if (c->sport == psm && !bacmp(&c->src, src))
2018c2ecf20Sopenharmony_ci			return c;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci	return NULL;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ciint l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	int err;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	write_lock(&chan_list_lock);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (psm && __l2cap_global_chan_by_addr(psm, src, chan->src_type)) {
2138c2ecf20Sopenharmony_ci		err = -EADDRINUSE;
2148c2ecf20Sopenharmony_ci		goto done;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (psm) {
2188c2ecf20Sopenharmony_ci		chan->psm = psm;
2198c2ecf20Sopenharmony_ci		chan->sport = psm;
2208c2ecf20Sopenharmony_ci		err = 0;
2218c2ecf20Sopenharmony_ci	} else {
2228c2ecf20Sopenharmony_ci		u16 p, start, end, incr;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci		if (chan->src_type == BDADDR_BREDR) {
2258c2ecf20Sopenharmony_ci			start = L2CAP_PSM_DYN_START;
2268c2ecf20Sopenharmony_ci			end = L2CAP_PSM_AUTO_END;
2278c2ecf20Sopenharmony_ci			incr = 2;
2288c2ecf20Sopenharmony_ci		} else {
2298c2ecf20Sopenharmony_ci			start = L2CAP_PSM_LE_DYN_START;
2308c2ecf20Sopenharmony_ci			end = L2CAP_PSM_LE_DYN_END;
2318c2ecf20Sopenharmony_ci			incr = 1;
2328c2ecf20Sopenharmony_ci		}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		err = -EINVAL;
2358c2ecf20Sopenharmony_ci		for (p = start; p <= end; p += incr)
2368c2ecf20Sopenharmony_ci			if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src,
2378c2ecf20Sopenharmony_ci							 chan->src_type)) {
2388c2ecf20Sopenharmony_ci				chan->psm   = cpu_to_le16(p);
2398c2ecf20Sopenharmony_ci				chan->sport = cpu_to_le16(p);
2408c2ecf20Sopenharmony_ci				err = 0;
2418c2ecf20Sopenharmony_ci				break;
2428c2ecf20Sopenharmony_ci			}
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cidone:
2468c2ecf20Sopenharmony_ci	write_unlock(&chan_list_lock);
2478c2ecf20Sopenharmony_ci	return err;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2cap_add_psm);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ciint l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid)
2528c2ecf20Sopenharmony_ci{
2538c2ecf20Sopenharmony_ci	write_lock(&chan_list_lock);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	/* Override the defaults (which are for conn-oriented) */
2568c2ecf20Sopenharmony_ci	chan->omtu = L2CAP_DEFAULT_MTU;
2578c2ecf20Sopenharmony_ci	chan->chan_type = L2CAP_CHAN_FIXED;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	chan->scid = scid;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	write_unlock(&chan_list_lock);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return 0;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic u16 l2cap_alloc_cid(struct l2cap_conn *conn)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	u16 cid, dyn_end;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (conn->hcon->type == LE_LINK)
2718c2ecf20Sopenharmony_ci		dyn_end = L2CAP_CID_LE_DYN_END;
2728c2ecf20Sopenharmony_ci	else
2738c2ecf20Sopenharmony_ci		dyn_end = L2CAP_CID_DYN_END;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	for (cid = L2CAP_CID_DYN_START; cid <= dyn_end; cid++) {
2768c2ecf20Sopenharmony_ci		if (!__l2cap_get_chan_by_scid(conn, cid))
2778c2ecf20Sopenharmony_ci			return cid;
2788c2ecf20Sopenharmony_ci	}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return 0;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic void l2cap_state_change(struct l2cap_chan *chan, int state)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
2868c2ecf20Sopenharmony_ci	       state_to_string(state));
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	chan->state = state;
2898c2ecf20Sopenharmony_ci	chan->ops->state_change(chan, state, 0);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic inline void l2cap_state_change_and_error(struct l2cap_chan *chan,
2938c2ecf20Sopenharmony_ci						int state, int err)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	chan->state = state;
2968c2ecf20Sopenharmony_ci	chan->ops->state_change(chan, chan->state, err);
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	chan->ops->state_change(chan, chan->state, err);
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic void __set_retrans_timer(struct l2cap_chan *chan)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	if (!delayed_work_pending(&chan->monitor_timer) &&
3078c2ecf20Sopenharmony_ci	    chan->retrans_timeout) {
3088c2ecf20Sopenharmony_ci		l2cap_set_timer(chan, &chan->retrans_timer,
3098c2ecf20Sopenharmony_ci				msecs_to_jiffies(chan->retrans_timeout));
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic void __set_monitor_timer(struct l2cap_chan *chan)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	__clear_retrans_timer(chan);
3168c2ecf20Sopenharmony_ci	if (chan->monitor_timeout) {
3178c2ecf20Sopenharmony_ci		l2cap_set_timer(chan, &chan->monitor_timer,
3188c2ecf20Sopenharmony_ci				msecs_to_jiffies(chan->monitor_timeout));
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic struct sk_buff *l2cap_ertm_seq_in_queue(struct sk_buff_head *head,
3238c2ecf20Sopenharmony_ci					       u16 seq)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	skb_queue_walk(head, skb) {
3288c2ecf20Sopenharmony_ci		if (bt_cb(skb)->l2cap.txseq == seq)
3298c2ecf20Sopenharmony_ci			return skb;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return NULL;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci/* ---- L2CAP sequence number lists ---- */
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/* For ERTM, ordered lists of sequence numbers must be tracked for
3388c2ecf20Sopenharmony_ci * SREJ requests that are received and for frames that are to be
3398c2ecf20Sopenharmony_ci * retransmitted. These seq_list functions implement a singly-linked
3408c2ecf20Sopenharmony_ci * list in an array, where membership in the list can also be checked
3418c2ecf20Sopenharmony_ci * in constant time. Items can also be added to the tail of the list
3428c2ecf20Sopenharmony_ci * and removed from the head in constant time, without further memory
3438c2ecf20Sopenharmony_ci * allocs or frees.
3448c2ecf20Sopenharmony_ci */
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	size_t alloc_size, i;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/* Allocated size is a power of 2 to map sequence numbers
3518c2ecf20Sopenharmony_ci	 * (which may be up to 14 bits) in to a smaller array that is
3528c2ecf20Sopenharmony_ci	 * sized for the negotiated ERTM transmit windows.
3538c2ecf20Sopenharmony_ci	 */
3548c2ecf20Sopenharmony_ci	alloc_size = roundup_pow_of_two(size);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	seq_list->list = kmalloc_array(alloc_size, sizeof(u16), GFP_KERNEL);
3578c2ecf20Sopenharmony_ci	if (!seq_list->list)
3588c2ecf20Sopenharmony_ci		return -ENOMEM;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	seq_list->mask = alloc_size - 1;
3618c2ecf20Sopenharmony_ci	seq_list->head = L2CAP_SEQ_LIST_CLEAR;
3628c2ecf20Sopenharmony_ci	seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
3638c2ecf20Sopenharmony_ci	for (i = 0; i < alloc_size; i++)
3648c2ecf20Sopenharmony_ci		seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	return 0;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic inline void l2cap_seq_list_free(struct l2cap_seq_list *seq_list)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	kfree(seq_list->list);
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list,
3758c2ecf20Sopenharmony_ci					   u16 seq)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	/* Constant-time check for list membership */
3788c2ecf20Sopenharmony_ci	return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	u16 seq = seq_list->head;
3848c2ecf20Sopenharmony_ci	u16 mask = seq_list->mask;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	seq_list->head = seq_list->list[seq & mask];
3878c2ecf20Sopenharmony_ci	seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (seq_list->head == L2CAP_SEQ_LIST_TAIL) {
3908c2ecf20Sopenharmony_ci		seq_list->head = L2CAP_SEQ_LIST_CLEAR;
3918c2ecf20Sopenharmony_ci		seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return seq;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	u16 i;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (seq_list->head == L2CAP_SEQ_LIST_CLEAR)
4028c2ecf20Sopenharmony_ci		return;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	for (i = 0; i <= seq_list->mask; i++)
4058c2ecf20Sopenharmony_ci		seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	seq_list->head = L2CAP_SEQ_LIST_CLEAR;
4088c2ecf20Sopenharmony_ci	seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	u16 mask = seq_list->mask;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* All appends happen in constant time */
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	if (seq_list->list[seq & mask] != L2CAP_SEQ_LIST_CLEAR)
4188c2ecf20Sopenharmony_ci		return;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (seq_list->tail == L2CAP_SEQ_LIST_CLEAR)
4218c2ecf20Sopenharmony_ci		seq_list->head = seq;
4228c2ecf20Sopenharmony_ci	else
4238c2ecf20Sopenharmony_ci		seq_list->list[seq_list->tail & mask] = seq;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	seq_list->tail = seq;
4268c2ecf20Sopenharmony_ci	seq_list->list[seq & mask] = L2CAP_SEQ_LIST_TAIL;
4278c2ecf20Sopenharmony_ci}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_cistatic void l2cap_chan_timeout(struct work_struct *work)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
4328c2ecf20Sopenharmony_ci					       chan_timer.work);
4338c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
4348c2ecf20Sopenharmony_ci	int reason;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	if (!conn)
4398c2ecf20Sopenharmony_ci		return;
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
4428c2ecf20Sopenharmony_ci	/* __set_chan_timer() calls l2cap_chan_hold(chan) while scheduling
4438c2ecf20Sopenharmony_ci	 * this work. No need to call l2cap_chan_hold(chan) here again.
4448c2ecf20Sopenharmony_ci	 */
4458c2ecf20Sopenharmony_ci	l2cap_chan_lock(chan);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
4488c2ecf20Sopenharmony_ci		reason = ECONNREFUSED;
4498c2ecf20Sopenharmony_ci	else if (chan->state == BT_CONNECT &&
4508c2ecf20Sopenharmony_ci		 chan->sec_level != BT_SECURITY_SDP)
4518c2ecf20Sopenharmony_ci		reason = ECONNREFUSED;
4528c2ecf20Sopenharmony_ci	else
4538c2ecf20Sopenharmony_ci		reason = ETIMEDOUT;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	l2cap_chan_close(chan, reason);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	chan->ops->close(chan);
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
4608c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistruct l2cap_chan *l2cap_chan_create(void)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
4708c2ecf20Sopenharmony_ci	if (!chan)
4718c2ecf20Sopenharmony_ci		return NULL;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	skb_queue_head_init(&chan->tx_q);
4748c2ecf20Sopenharmony_ci	skb_queue_head_init(&chan->srej_q);
4758c2ecf20Sopenharmony_ci	mutex_init(&chan->lock);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	/* Set default lock nesting level */
4788c2ecf20Sopenharmony_ci	atomic_set(&chan->nesting, L2CAP_NESTING_NORMAL);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	write_lock(&chan_list_lock);
4818c2ecf20Sopenharmony_ci	list_add(&chan->global_l, &chan_list);
4828c2ecf20Sopenharmony_ci	write_unlock(&chan_list_lock);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
4858c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
4868c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
4878c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	chan->state = BT_OPEN;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	kref_init(&chan->kref);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	/* This flag is cleared in l2cap_chan_ready() */
4948c2ecf20Sopenharmony_ci	set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	return chan;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2cap_chan_create);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic void l2cap_chan_destroy(struct kref *kref)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	struct l2cap_chan *chan = container_of(kref, struct l2cap_chan, kref);
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	write_lock(&chan_list_lock);
5098c2ecf20Sopenharmony_ci	list_del(&chan->global_l);
5108c2ecf20Sopenharmony_ci	write_unlock(&chan_list_lock);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	kfree(chan);
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_civoid l2cap_chan_hold(struct l2cap_chan *c)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	BT_DBG("chan %p orig refcnt %d", c, kref_read(&c->kref));
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	kref_get(&c->kref);
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistruct l2cap_chan *l2cap_chan_hold_unless_zero(struct l2cap_chan *c)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	BT_DBG("chan %p orig refcnt %u", c, kref_read(&c->kref));
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	if (!kref_get_unless_zero(&c->kref))
5278c2ecf20Sopenharmony_ci		return NULL;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	return c;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_civoid l2cap_chan_put(struct l2cap_chan *c)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	BT_DBG("chan %p orig refcnt %d", c, kref_read(&c->kref));
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	kref_put(&c->kref, l2cap_chan_destroy);
5378c2ecf20Sopenharmony_ci}
5388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2cap_chan_put);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_civoid l2cap_chan_set_defaults(struct l2cap_chan *chan)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	chan->fcs  = L2CAP_FCS_CRC16;
5438c2ecf20Sopenharmony_ci	chan->max_tx = L2CAP_DEFAULT_MAX_TX;
5448c2ecf20Sopenharmony_ci	chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
5458c2ecf20Sopenharmony_ci	chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
5468c2ecf20Sopenharmony_ci	chan->remote_max_tx = chan->max_tx;
5478c2ecf20Sopenharmony_ci	chan->remote_tx_win = chan->tx_win;
5488c2ecf20Sopenharmony_ci	chan->ack_win = L2CAP_DEFAULT_TX_WINDOW;
5498c2ecf20Sopenharmony_ci	chan->sec_level = BT_SECURITY_LOW;
5508c2ecf20Sopenharmony_ci	chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
5518c2ecf20Sopenharmony_ci	chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
5528c2ecf20Sopenharmony_ci	chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	chan->conf_state = 0;
5558c2ecf20Sopenharmony_ci	set_bit(CONF_NOT_COMPLETE, &chan->conf_state);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2cap_chan_set_defaults);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic void l2cap_le_flowctl_init(struct l2cap_chan *chan, u16 tx_credits)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	chan->sdu = NULL;
5648c2ecf20Sopenharmony_ci	chan->sdu_last_frag = NULL;
5658c2ecf20Sopenharmony_ci	chan->sdu_len = 0;
5668c2ecf20Sopenharmony_ci	chan->tx_credits = tx_credits;
5678c2ecf20Sopenharmony_ci	/* Derive MPS from connection MTU to stop HCI fragmentation */
5688c2ecf20Sopenharmony_ci	chan->mps = min_t(u16, chan->imtu, chan->conn->mtu - L2CAP_HDR_SIZE);
5698c2ecf20Sopenharmony_ci	/* Give enough credits for a full packet */
5708c2ecf20Sopenharmony_ci	chan->rx_credits = (chan->imtu / chan->mps) + 1;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	skb_queue_head_init(&chan->tx_q);
5738c2ecf20Sopenharmony_ci}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_cistatic void l2cap_ecred_init(struct l2cap_chan *chan, u16 tx_credits)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	l2cap_le_flowctl_init(chan, tx_credits);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/* L2CAP implementations shall support a minimum MPS of 64 octets */
5808c2ecf20Sopenharmony_ci	if (chan->mps < L2CAP_ECRED_MIN_MPS) {
5818c2ecf20Sopenharmony_ci		chan->mps = L2CAP_ECRED_MIN_MPS;
5828c2ecf20Sopenharmony_ci		chan->rx_credits = (chan->imtu / chan->mps) + 1;
5838c2ecf20Sopenharmony_ci	}
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_civoid __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
5898c2ecf20Sopenharmony_ci	       __le16_to_cpu(chan->psm), chan->dcid);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	chan->conn = conn;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	switch (chan->chan_type) {
5968c2ecf20Sopenharmony_ci	case L2CAP_CHAN_CONN_ORIENTED:
5978c2ecf20Sopenharmony_ci		/* Alloc CID for connection-oriented socket */
5988c2ecf20Sopenharmony_ci		chan->scid = l2cap_alloc_cid(conn);
5998c2ecf20Sopenharmony_ci		if (conn->hcon->type == ACL_LINK)
6008c2ecf20Sopenharmony_ci			chan->omtu = L2CAP_DEFAULT_MTU;
6018c2ecf20Sopenharmony_ci		break;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	case L2CAP_CHAN_CONN_LESS:
6048c2ecf20Sopenharmony_ci		/* Connectionless socket */
6058c2ecf20Sopenharmony_ci		chan->scid = L2CAP_CID_CONN_LESS;
6068c2ecf20Sopenharmony_ci		chan->dcid = L2CAP_CID_CONN_LESS;
6078c2ecf20Sopenharmony_ci		chan->omtu = L2CAP_DEFAULT_MTU;
6088c2ecf20Sopenharmony_ci		break;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	case L2CAP_CHAN_FIXED:
6118c2ecf20Sopenharmony_ci		/* Caller will set CID and CID specific MTU values */
6128c2ecf20Sopenharmony_ci		break;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	default:
6158c2ecf20Sopenharmony_ci		/* Raw socket can send/recv signalling messages only */
6168c2ecf20Sopenharmony_ci		chan->scid = L2CAP_CID_SIGNALING;
6178c2ecf20Sopenharmony_ci		chan->dcid = L2CAP_CID_SIGNALING;
6188c2ecf20Sopenharmony_ci		chan->omtu = L2CAP_DEFAULT_MTU;
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	chan->local_id		= L2CAP_BESTEFFORT_ID;
6228c2ecf20Sopenharmony_ci	chan->local_stype	= L2CAP_SERV_BESTEFFORT;
6238c2ecf20Sopenharmony_ci	chan->local_msdu	= L2CAP_DEFAULT_MAX_SDU_SIZE;
6248c2ecf20Sopenharmony_ci	chan->local_sdu_itime	= L2CAP_DEFAULT_SDU_ITIME;
6258c2ecf20Sopenharmony_ci	chan->local_acc_lat	= L2CAP_DEFAULT_ACC_LAT;
6268c2ecf20Sopenharmony_ci	chan->local_flush_to	= L2CAP_EFS_DEFAULT_FLUSH_TO;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	l2cap_chan_hold(chan);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	/* Only keep a reference for fixed channels if they requested it */
6318c2ecf20Sopenharmony_ci	if (chan->chan_type != L2CAP_CHAN_FIXED ||
6328c2ecf20Sopenharmony_ci	    test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
6338c2ecf20Sopenharmony_ci		hci_conn_hold(conn->hcon);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	list_add(&chan->list, &conn->chan_l);
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_civoid l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
6418c2ecf20Sopenharmony_ci	__l2cap_chan_add(conn, chan);
6428c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
6438c2ecf20Sopenharmony_ci}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_civoid l2cap_chan_del(struct l2cap_chan *chan, int err)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	__clear_chan_timer(chan);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	BT_DBG("chan %p, conn %p, err %d, state %s", chan, conn, err,
6528c2ecf20Sopenharmony_ci	       state_to_string(chan->state));
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	chan->ops->teardown(chan, err);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (conn) {
6578c2ecf20Sopenharmony_ci		struct amp_mgr *mgr = conn->hcon->amp_mgr;
6588c2ecf20Sopenharmony_ci		/* Delete from channel list */
6598c2ecf20Sopenharmony_ci		list_del(&chan->list);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci		l2cap_chan_put(chan);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci		chan->conn = NULL;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		/* Reference was only held for non-fixed channels or
6668c2ecf20Sopenharmony_ci		 * fixed channels that explicitly requested it using the
6678c2ecf20Sopenharmony_ci		 * FLAG_HOLD_HCI_CONN flag.
6688c2ecf20Sopenharmony_ci		 */
6698c2ecf20Sopenharmony_ci		if (chan->chan_type != L2CAP_CHAN_FIXED ||
6708c2ecf20Sopenharmony_ci		    test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
6718c2ecf20Sopenharmony_ci			hci_conn_drop(conn->hcon);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci		if (mgr && mgr->bredr_chan == chan)
6748c2ecf20Sopenharmony_ci			mgr->bredr_chan = NULL;
6758c2ecf20Sopenharmony_ci	}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	if (chan->hs_hchan) {
6788c2ecf20Sopenharmony_ci		struct hci_chan *hs_hchan = chan->hs_hchan;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci		BT_DBG("chan %p disconnect hs_hchan %p", chan, hs_hchan);
6818c2ecf20Sopenharmony_ci		amp_disconnect_logical_link(hs_hchan);
6828c2ecf20Sopenharmony_ci	}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
6858c2ecf20Sopenharmony_ci		return;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	switch(chan->mode) {
6888c2ecf20Sopenharmony_ci	case L2CAP_MODE_BASIC:
6898c2ecf20Sopenharmony_ci		break;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	case L2CAP_MODE_LE_FLOWCTL:
6928c2ecf20Sopenharmony_ci	case L2CAP_MODE_EXT_FLOWCTL:
6938c2ecf20Sopenharmony_ci		skb_queue_purge(&chan->tx_q);
6948c2ecf20Sopenharmony_ci		break;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
6978c2ecf20Sopenharmony_ci		__clear_retrans_timer(chan);
6988c2ecf20Sopenharmony_ci		__clear_monitor_timer(chan);
6998c2ecf20Sopenharmony_ci		__clear_ack_timer(chan);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		skb_queue_purge(&chan->srej_q);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci		l2cap_seq_list_free(&chan->srej_list);
7048c2ecf20Sopenharmony_ci		l2cap_seq_list_free(&chan->retrans_list);
7058c2ecf20Sopenharmony_ci		fallthrough;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
7088c2ecf20Sopenharmony_ci		skb_queue_purge(&chan->tx_q);
7098c2ecf20Sopenharmony_ci		break;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	return;
7138c2ecf20Sopenharmony_ci}
7148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2cap_chan_del);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cistatic void __l2cap_chan_list_id(struct l2cap_conn *conn, u16 id,
7178c2ecf20Sopenharmony_ci				 l2cap_chan_func_t func, void *data)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	struct l2cap_chan *chan, *l;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
7228c2ecf20Sopenharmony_ci		if (chan->ident == id)
7238c2ecf20Sopenharmony_ci			func(chan, data);
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic void __l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
7288c2ecf20Sopenharmony_ci			      void *data)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	list_for_each_entry(chan, &conn->chan_l, list) {
7338c2ecf20Sopenharmony_ci		func(chan, data);
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_civoid l2cap_chan_list(struct l2cap_conn *conn, l2cap_chan_func_t func,
7388c2ecf20Sopenharmony_ci		     void *data)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	if (!conn)
7418c2ecf20Sopenharmony_ci		return;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
7448c2ecf20Sopenharmony_ci	__l2cap_chan_list(conn, func, data);
7458c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2cap_chan_list);
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic void l2cap_conn_update_id_addr(struct work_struct *work)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
7538c2ecf20Sopenharmony_ci					       id_addr_update_work);
7548c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
7558c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	list_for_each_entry(chan, &conn->chan_l, list) {
7608c2ecf20Sopenharmony_ci		l2cap_chan_lock(chan);
7618c2ecf20Sopenharmony_ci		bacpy(&chan->dst, &hcon->dst);
7628c2ecf20Sopenharmony_ci		chan->dst_type = bdaddr_dst_type(hcon);
7638c2ecf20Sopenharmony_ci		l2cap_chan_unlock(chan);
7648c2ecf20Sopenharmony_ci	}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_cistatic void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
7708c2ecf20Sopenharmony_ci{
7718c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
7728c2ecf20Sopenharmony_ci	struct l2cap_le_conn_rsp rsp;
7738c2ecf20Sopenharmony_ci	u16 result;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
7768c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_AUTHORIZATION;
7778c2ecf20Sopenharmony_ci	else
7788c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_BAD_PSM;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	l2cap_state_change(chan, BT_DISCONN);
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	rsp.dcid    = cpu_to_le16(chan->scid);
7838c2ecf20Sopenharmony_ci	rsp.mtu     = cpu_to_le16(chan->imtu);
7848c2ecf20Sopenharmony_ci	rsp.mps     = cpu_to_le16(chan->mps);
7858c2ecf20Sopenharmony_ci	rsp.credits = cpu_to_le16(chan->rx_credits);
7868c2ecf20Sopenharmony_ci	rsp.result  = cpu_to_le16(result);
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp),
7898c2ecf20Sopenharmony_ci		       &rsp);
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_cistatic void l2cap_chan_ecred_connect_reject(struct l2cap_chan *chan)
7938c2ecf20Sopenharmony_ci{
7948c2ecf20Sopenharmony_ci	l2cap_state_change(chan, BT_DISCONN);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	__l2cap_ecred_conn_rsp_defer(chan);
7978c2ecf20Sopenharmony_ci}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_cistatic void l2cap_chan_connect_reject(struct l2cap_chan *chan)
8008c2ecf20Sopenharmony_ci{
8018c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
8028c2ecf20Sopenharmony_ci	struct l2cap_conn_rsp rsp;
8038c2ecf20Sopenharmony_ci	u16 result;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
8068c2ecf20Sopenharmony_ci		result = L2CAP_CR_SEC_BLOCK;
8078c2ecf20Sopenharmony_ci	else
8088c2ecf20Sopenharmony_ci		result = L2CAP_CR_BAD_PSM;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	l2cap_state_change(chan, BT_DISCONN);
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	rsp.scid   = cpu_to_le16(chan->dcid);
8138c2ecf20Sopenharmony_ci	rsp.dcid   = cpu_to_le16(chan->scid);
8148c2ecf20Sopenharmony_ci	rsp.result = cpu_to_le16(result);
8158c2ecf20Sopenharmony_ci	rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_civoid l2cap_chan_close(struct l2cap_chan *chan, int reason)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	switch (chan->state) {
8278c2ecf20Sopenharmony_ci	case BT_LISTEN:
8288c2ecf20Sopenharmony_ci		chan->ops->teardown(chan, 0);
8298c2ecf20Sopenharmony_ci		break;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	case BT_CONNECTED:
8328c2ecf20Sopenharmony_ci	case BT_CONFIG:
8338c2ecf20Sopenharmony_ci		if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
8348c2ecf20Sopenharmony_ci			__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
8358c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, reason);
8368c2ecf20Sopenharmony_ci		} else
8378c2ecf20Sopenharmony_ci			l2cap_chan_del(chan, reason);
8388c2ecf20Sopenharmony_ci		break;
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	case BT_CONNECT2:
8418c2ecf20Sopenharmony_ci		if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
8428c2ecf20Sopenharmony_ci			if (conn->hcon->type == ACL_LINK)
8438c2ecf20Sopenharmony_ci				l2cap_chan_connect_reject(chan);
8448c2ecf20Sopenharmony_ci			else if (conn->hcon->type == LE_LINK) {
8458c2ecf20Sopenharmony_ci				switch (chan->mode) {
8468c2ecf20Sopenharmony_ci				case L2CAP_MODE_LE_FLOWCTL:
8478c2ecf20Sopenharmony_ci					l2cap_chan_le_connect_reject(chan);
8488c2ecf20Sopenharmony_ci					break;
8498c2ecf20Sopenharmony_ci				case L2CAP_MODE_EXT_FLOWCTL:
8508c2ecf20Sopenharmony_ci					l2cap_chan_ecred_connect_reject(chan);
8518c2ecf20Sopenharmony_ci					return;
8528c2ecf20Sopenharmony_ci				}
8538c2ecf20Sopenharmony_ci			}
8548c2ecf20Sopenharmony_ci		}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci		l2cap_chan_del(chan, reason);
8578c2ecf20Sopenharmony_ci		break;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	case BT_CONNECT:
8608c2ecf20Sopenharmony_ci	case BT_DISCONN:
8618c2ecf20Sopenharmony_ci		l2cap_chan_del(chan, reason);
8628c2ecf20Sopenharmony_ci		break;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	default:
8658c2ecf20Sopenharmony_ci		chan->ops->teardown(chan, 0);
8668c2ecf20Sopenharmony_ci		break;
8678c2ecf20Sopenharmony_ci	}
8688c2ecf20Sopenharmony_ci}
8698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(l2cap_chan_close);
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_cistatic inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	switch (chan->chan_type) {
8748c2ecf20Sopenharmony_ci	case L2CAP_CHAN_RAW:
8758c2ecf20Sopenharmony_ci		switch (chan->sec_level) {
8768c2ecf20Sopenharmony_ci		case BT_SECURITY_HIGH:
8778c2ecf20Sopenharmony_ci		case BT_SECURITY_FIPS:
8788c2ecf20Sopenharmony_ci			return HCI_AT_DEDICATED_BONDING_MITM;
8798c2ecf20Sopenharmony_ci		case BT_SECURITY_MEDIUM:
8808c2ecf20Sopenharmony_ci			return HCI_AT_DEDICATED_BONDING;
8818c2ecf20Sopenharmony_ci		default:
8828c2ecf20Sopenharmony_ci			return HCI_AT_NO_BONDING;
8838c2ecf20Sopenharmony_ci		}
8848c2ecf20Sopenharmony_ci		break;
8858c2ecf20Sopenharmony_ci	case L2CAP_CHAN_CONN_LESS:
8868c2ecf20Sopenharmony_ci		if (chan->psm == cpu_to_le16(L2CAP_PSM_3DSP)) {
8878c2ecf20Sopenharmony_ci			if (chan->sec_level == BT_SECURITY_LOW)
8888c2ecf20Sopenharmony_ci				chan->sec_level = BT_SECURITY_SDP;
8898c2ecf20Sopenharmony_ci		}
8908c2ecf20Sopenharmony_ci		if (chan->sec_level == BT_SECURITY_HIGH ||
8918c2ecf20Sopenharmony_ci		    chan->sec_level == BT_SECURITY_FIPS)
8928c2ecf20Sopenharmony_ci			return HCI_AT_NO_BONDING_MITM;
8938c2ecf20Sopenharmony_ci		else
8948c2ecf20Sopenharmony_ci			return HCI_AT_NO_BONDING;
8958c2ecf20Sopenharmony_ci		break;
8968c2ecf20Sopenharmony_ci	case L2CAP_CHAN_CONN_ORIENTED:
8978c2ecf20Sopenharmony_ci		if (chan->psm == cpu_to_le16(L2CAP_PSM_SDP)) {
8988c2ecf20Sopenharmony_ci			if (chan->sec_level == BT_SECURITY_LOW)
8998c2ecf20Sopenharmony_ci				chan->sec_level = BT_SECURITY_SDP;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci			if (chan->sec_level == BT_SECURITY_HIGH ||
9028c2ecf20Sopenharmony_ci			    chan->sec_level == BT_SECURITY_FIPS)
9038c2ecf20Sopenharmony_ci				return HCI_AT_NO_BONDING_MITM;
9048c2ecf20Sopenharmony_ci			else
9058c2ecf20Sopenharmony_ci				return HCI_AT_NO_BONDING;
9068c2ecf20Sopenharmony_ci		}
9078c2ecf20Sopenharmony_ci		fallthrough;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	default:
9108c2ecf20Sopenharmony_ci		switch (chan->sec_level) {
9118c2ecf20Sopenharmony_ci		case BT_SECURITY_HIGH:
9128c2ecf20Sopenharmony_ci		case BT_SECURITY_FIPS:
9138c2ecf20Sopenharmony_ci			return HCI_AT_GENERAL_BONDING_MITM;
9148c2ecf20Sopenharmony_ci		case BT_SECURITY_MEDIUM:
9158c2ecf20Sopenharmony_ci			return HCI_AT_GENERAL_BONDING;
9168c2ecf20Sopenharmony_ci		default:
9178c2ecf20Sopenharmony_ci			return HCI_AT_NO_BONDING;
9188c2ecf20Sopenharmony_ci		}
9198c2ecf20Sopenharmony_ci		break;
9208c2ecf20Sopenharmony_ci	}
9218c2ecf20Sopenharmony_ci}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci/* Service level security */
9248c2ecf20Sopenharmony_ciint l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator)
9258c2ecf20Sopenharmony_ci{
9268c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
9278c2ecf20Sopenharmony_ci	__u8 auth_type;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	if (conn->hcon->type == LE_LINK)
9308c2ecf20Sopenharmony_ci		return smp_conn_security(conn->hcon, chan->sec_level);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	auth_type = l2cap_get_auth_type(chan);
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	return hci_conn_security(conn->hcon, chan->sec_level, auth_type,
9358c2ecf20Sopenharmony_ci				 initiator);
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic u8 l2cap_get_ident(struct l2cap_conn *conn)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	u8 id;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	/* Get next available identificator.
9438c2ecf20Sopenharmony_ci	 *    1 - 128 are used by kernel.
9448c2ecf20Sopenharmony_ci	 *  129 - 199 are reserved.
9458c2ecf20Sopenharmony_ci	 *  200 - 254 are used by utilities like l2ping, etc.
9468c2ecf20Sopenharmony_ci	 */
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	mutex_lock(&conn->ident_lock);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	if (++conn->tx_ident > 128)
9518c2ecf20Sopenharmony_ci		conn->tx_ident = 1;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	id = conn->tx_ident;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	mutex_unlock(&conn->ident_lock);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	return id;
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_cistatic void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
9618c2ecf20Sopenharmony_ci			   void *data)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
9648c2ecf20Sopenharmony_ci	u8 flags;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	BT_DBG("code 0x%2.2x", code);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	if (!skb)
9698c2ecf20Sopenharmony_ci		return;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	/* Use NO_FLUSH if supported or we have an LE link (which does
9728c2ecf20Sopenharmony_ci	 * not support auto-flushing packets) */
9738c2ecf20Sopenharmony_ci	if (lmp_no_flush_capable(conn->hcon->hdev) ||
9748c2ecf20Sopenharmony_ci	    conn->hcon->type == LE_LINK)
9758c2ecf20Sopenharmony_ci		flags = ACL_START_NO_FLUSH;
9768c2ecf20Sopenharmony_ci	else
9778c2ecf20Sopenharmony_ci		flags = ACL_START;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
9808c2ecf20Sopenharmony_ci	skb->priority = HCI_PRIO_MAX;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	hci_send_acl(conn->hchan, skb, flags);
9838c2ecf20Sopenharmony_ci}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_cistatic bool __chan_is_moving(struct l2cap_chan *chan)
9868c2ecf20Sopenharmony_ci{
9878c2ecf20Sopenharmony_ci	return chan->move_state != L2CAP_MOVE_STABLE &&
9888c2ecf20Sopenharmony_ci	       chan->move_state != L2CAP_MOVE_WAIT_PREPARE;
9898c2ecf20Sopenharmony_ci}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_cistatic void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	struct hci_conn *hcon = chan->conn->hcon;
9948c2ecf20Sopenharmony_ci	u16 flags;
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
9978c2ecf20Sopenharmony_ci	       skb->priority);
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	if (chan->hs_hcon && !__chan_is_moving(chan)) {
10008c2ecf20Sopenharmony_ci		if (chan->hs_hchan)
10018c2ecf20Sopenharmony_ci			hci_send_acl(chan->hs_hchan, skb, ACL_COMPLETE);
10028c2ecf20Sopenharmony_ci		else
10038c2ecf20Sopenharmony_ci			kfree_skb(skb);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci		return;
10068c2ecf20Sopenharmony_ci	}
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/* Use NO_FLUSH for LE links (where this is the only option) or
10098c2ecf20Sopenharmony_ci	 * if the BR/EDR link supports it and flushing has not been
10108c2ecf20Sopenharmony_ci	 * explicitly requested (through FLAG_FLUSHABLE).
10118c2ecf20Sopenharmony_ci	 */
10128c2ecf20Sopenharmony_ci	if (hcon->type == LE_LINK ||
10138c2ecf20Sopenharmony_ci	    (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
10148c2ecf20Sopenharmony_ci	     lmp_no_flush_capable(hcon->hdev)))
10158c2ecf20Sopenharmony_ci		flags = ACL_START_NO_FLUSH;
10168c2ecf20Sopenharmony_ci	else
10178c2ecf20Sopenharmony_ci		flags = ACL_START;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
10208c2ecf20Sopenharmony_ci	hci_send_acl(chan->conn->hchan, skb, flags);
10218c2ecf20Sopenharmony_ci}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_cistatic void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control)
10248c2ecf20Sopenharmony_ci{
10258c2ecf20Sopenharmony_ci	control->reqseq = (enh & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
10268c2ecf20Sopenharmony_ci	control->final = (enh & L2CAP_CTRL_FINAL) >> L2CAP_CTRL_FINAL_SHIFT;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	if (enh & L2CAP_CTRL_FRAME_TYPE) {
10298c2ecf20Sopenharmony_ci		/* S-Frame */
10308c2ecf20Sopenharmony_ci		control->sframe = 1;
10318c2ecf20Sopenharmony_ci		control->poll = (enh & L2CAP_CTRL_POLL) >> L2CAP_CTRL_POLL_SHIFT;
10328c2ecf20Sopenharmony_ci		control->super = (enh & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci		control->sar = 0;
10358c2ecf20Sopenharmony_ci		control->txseq = 0;
10368c2ecf20Sopenharmony_ci	} else {
10378c2ecf20Sopenharmony_ci		/* I-Frame */
10388c2ecf20Sopenharmony_ci		control->sframe = 0;
10398c2ecf20Sopenharmony_ci		control->sar = (enh & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
10408c2ecf20Sopenharmony_ci		control->txseq = (enh & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci		control->poll = 0;
10438c2ecf20Sopenharmony_ci		control->super = 0;
10448c2ecf20Sopenharmony_ci	}
10458c2ecf20Sopenharmony_ci}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_cistatic void __unpack_extended_control(u32 ext, struct l2cap_ctrl *control)
10488c2ecf20Sopenharmony_ci{
10498c2ecf20Sopenharmony_ci	control->reqseq = (ext & L2CAP_EXT_CTRL_REQSEQ) >> L2CAP_EXT_CTRL_REQSEQ_SHIFT;
10508c2ecf20Sopenharmony_ci	control->final = (ext & L2CAP_EXT_CTRL_FINAL) >> L2CAP_EXT_CTRL_FINAL_SHIFT;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	if (ext & L2CAP_EXT_CTRL_FRAME_TYPE) {
10538c2ecf20Sopenharmony_ci		/* S-Frame */
10548c2ecf20Sopenharmony_ci		control->sframe = 1;
10558c2ecf20Sopenharmony_ci		control->poll = (ext & L2CAP_EXT_CTRL_POLL) >> L2CAP_EXT_CTRL_POLL_SHIFT;
10568c2ecf20Sopenharmony_ci		control->super = (ext & L2CAP_EXT_CTRL_SUPERVISE) >> L2CAP_EXT_CTRL_SUPER_SHIFT;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci		control->sar = 0;
10598c2ecf20Sopenharmony_ci		control->txseq = 0;
10608c2ecf20Sopenharmony_ci	} else {
10618c2ecf20Sopenharmony_ci		/* I-Frame */
10628c2ecf20Sopenharmony_ci		control->sframe = 0;
10638c2ecf20Sopenharmony_ci		control->sar = (ext & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
10648c2ecf20Sopenharmony_ci		control->txseq = (ext & L2CAP_EXT_CTRL_TXSEQ) >> L2CAP_EXT_CTRL_TXSEQ_SHIFT;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci		control->poll = 0;
10678c2ecf20Sopenharmony_ci		control->super = 0;
10688c2ecf20Sopenharmony_ci	}
10698c2ecf20Sopenharmony_ci}
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_cistatic inline void __unpack_control(struct l2cap_chan *chan,
10728c2ecf20Sopenharmony_ci				    struct sk_buff *skb)
10738c2ecf20Sopenharmony_ci{
10748c2ecf20Sopenharmony_ci	if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
10758c2ecf20Sopenharmony_ci		__unpack_extended_control(get_unaligned_le32(skb->data),
10768c2ecf20Sopenharmony_ci					  &bt_cb(skb)->l2cap);
10778c2ecf20Sopenharmony_ci		skb_pull(skb, L2CAP_EXT_CTRL_SIZE);
10788c2ecf20Sopenharmony_ci	} else {
10798c2ecf20Sopenharmony_ci		__unpack_enhanced_control(get_unaligned_le16(skb->data),
10808c2ecf20Sopenharmony_ci					  &bt_cb(skb)->l2cap);
10818c2ecf20Sopenharmony_ci		skb_pull(skb, L2CAP_ENH_CTRL_SIZE);
10828c2ecf20Sopenharmony_ci	}
10838c2ecf20Sopenharmony_ci}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_cistatic u32 __pack_extended_control(struct l2cap_ctrl *control)
10868c2ecf20Sopenharmony_ci{
10878c2ecf20Sopenharmony_ci	u32 packed;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT;
10908c2ecf20Sopenharmony_ci	packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	if (control->sframe) {
10938c2ecf20Sopenharmony_ci		packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT;
10948c2ecf20Sopenharmony_ci		packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT;
10958c2ecf20Sopenharmony_ci		packed |= L2CAP_EXT_CTRL_FRAME_TYPE;
10968c2ecf20Sopenharmony_ci	} else {
10978c2ecf20Sopenharmony_ci		packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT;
10988c2ecf20Sopenharmony_ci		packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT;
10998c2ecf20Sopenharmony_ci	}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	return packed;
11028c2ecf20Sopenharmony_ci}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_cistatic u16 __pack_enhanced_control(struct l2cap_ctrl *control)
11058c2ecf20Sopenharmony_ci{
11068c2ecf20Sopenharmony_ci	u16 packed;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT;
11098c2ecf20Sopenharmony_ci	packed |= control->final << L2CAP_CTRL_FINAL_SHIFT;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	if (control->sframe) {
11128c2ecf20Sopenharmony_ci		packed |= control->poll << L2CAP_CTRL_POLL_SHIFT;
11138c2ecf20Sopenharmony_ci		packed |= control->super << L2CAP_CTRL_SUPER_SHIFT;
11148c2ecf20Sopenharmony_ci		packed |= L2CAP_CTRL_FRAME_TYPE;
11158c2ecf20Sopenharmony_ci	} else {
11168c2ecf20Sopenharmony_ci		packed |= control->sar << L2CAP_CTRL_SAR_SHIFT;
11178c2ecf20Sopenharmony_ci		packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT;
11188c2ecf20Sopenharmony_ci	}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	return packed;
11218c2ecf20Sopenharmony_ci}
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_cistatic inline void __pack_control(struct l2cap_chan *chan,
11248c2ecf20Sopenharmony_ci				  struct l2cap_ctrl *control,
11258c2ecf20Sopenharmony_ci				  struct sk_buff *skb)
11268c2ecf20Sopenharmony_ci{
11278c2ecf20Sopenharmony_ci	if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
11288c2ecf20Sopenharmony_ci		put_unaligned_le32(__pack_extended_control(control),
11298c2ecf20Sopenharmony_ci				   skb->data + L2CAP_HDR_SIZE);
11308c2ecf20Sopenharmony_ci	} else {
11318c2ecf20Sopenharmony_ci		put_unaligned_le16(__pack_enhanced_control(control),
11328c2ecf20Sopenharmony_ci				   skb->data + L2CAP_HDR_SIZE);
11338c2ecf20Sopenharmony_ci	}
11348c2ecf20Sopenharmony_ci}
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_cistatic inline unsigned int __ertm_hdr_size(struct l2cap_chan *chan)
11378c2ecf20Sopenharmony_ci{
11388c2ecf20Sopenharmony_ci	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
11398c2ecf20Sopenharmony_ci		return L2CAP_EXT_HDR_SIZE;
11408c2ecf20Sopenharmony_ci	else
11418c2ecf20Sopenharmony_ci		return L2CAP_ENH_HDR_SIZE;
11428c2ecf20Sopenharmony_ci}
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_cistatic struct sk_buff *l2cap_create_sframe_pdu(struct l2cap_chan *chan,
11458c2ecf20Sopenharmony_ci					       u32 control)
11468c2ecf20Sopenharmony_ci{
11478c2ecf20Sopenharmony_ci	struct sk_buff *skb;
11488c2ecf20Sopenharmony_ci	struct l2cap_hdr *lh;
11498c2ecf20Sopenharmony_ci	int hlen = __ertm_hdr_size(chan);
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	if (chan->fcs == L2CAP_FCS_CRC16)
11528c2ecf20Sopenharmony_ci		hlen += L2CAP_FCS_SIZE;
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	skb = bt_skb_alloc(hlen, GFP_KERNEL);
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	if (!skb)
11578c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	lh = skb_put(skb, L2CAP_HDR_SIZE);
11608c2ecf20Sopenharmony_ci	lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
11618c2ecf20Sopenharmony_ci	lh->cid = cpu_to_le16(chan->dcid);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
11648c2ecf20Sopenharmony_ci		put_unaligned_le32(control, skb_put(skb, L2CAP_EXT_CTRL_SIZE));
11658c2ecf20Sopenharmony_ci	else
11668c2ecf20Sopenharmony_ci		put_unaligned_le16(control, skb_put(skb, L2CAP_ENH_CTRL_SIZE));
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	if (chan->fcs == L2CAP_FCS_CRC16) {
11698c2ecf20Sopenharmony_ci		u16 fcs = crc16(0, (u8 *)skb->data, skb->len);
11708c2ecf20Sopenharmony_ci		put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
11718c2ecf20Sopenharmony_ci	}
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	skb->priority = HCI_PRIO_MAX;
11748c2ecf20Sopenharmony_ci	return skb;
11758c2ecf20Sopenharmony_ci}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_cistatic void l2cap_send_sframe(struct l2cap_chan *chan,
11788c2ecf20Sopenharmony_ci			      struct l2cap_ctrl *control)
11798c2ecf20Sopenharmony_ci{
11808c2ecf20Sopenharmony_ci	struct sk_buff *skb;
11818c2ecf20Sopenharmony_ci	u32 control_field;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p", chan, control);
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	if (!control->sframe)
11868c2ecf20Sopenharmony_ci		return;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if (__chan_is_moving(chan))
11898c2ecf20Sopenharmony_ci		return;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) &&
11928c2ecf20Sopenharmony_ci	    !control->poll)
11938c2ecf20Sopenharmony_ci		control->final = 1;
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	if (control->super == L2CAP_SUPER_RR)
11968c2ecf20Sopenharmony_ci		clear_bit(CONN_RNR_SENT, &chan->conn_state);
11978c2ecf20Sopenharmony_ci	else if (control->super == L2CAP_SUPER_RNR)
11988c2ecf20Sopenharmony_ci		set_bit(CONN_RNR_SENT, &chan->conn_state);
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	if (control->super != L2CAP_SUPER_SREJ) {
12018c2ecf20Sopenharmony_ci		chan->last_acked_seq = control->reqseq;
12028c2ecf20Sopenharmony_ci		__clear_ack_timer(chan);
12038c2ecf20Sopenharmony_ci	}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	BT_DBG("reqseq %d, final %d, poll %d, super %d", control->reqseq,
12068c2ecf20Sopenharmony_ci	       control->final, control->poll, control->super);
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
12098c2ecf20Sopenharmony_ci		control_field = __pack_extended_control(control);
12108c2ecf20Sopenharmony_ci	else
12118c2ecf20Sopenharmony_ci		control_field = __pack_enhanced_control(control);
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	skb = l2cap_create_sframe_pdu(chan, control_field);
12148c2ecf20Sopenharmony_ci	if (!IS_ERR(skb))
12158c2ecf20Sopenharmony_ci		l2cap_do_send(chan, skb);
12168c2ecf20Sopenharmony_ci}
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_cistatic void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, bool poll)
12198c2ecf20Sopenharmony_ci{
12208c2ecf20Sopenharmony_ci	struct l2cap_ctrl control;
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	BT_DBG("chan %p, poll %d", chan, poll);
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	memset(&control, 0, sizeof(control));
12258c2ecf20Sopenharmony_ci	control.sframe = 1;
12268c2ecf20Sopenharmony_ci	control.poll = poll;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
12298c2ecf20Sopenharmony_ci		control.super = L2CAP_SUPER_RNR;
12308c2ecf20Sopenharmony_ci	else
12318c2ecf20Sopenharmony_ci		control.super = L2CAP_SUPER_RR;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	control.reqseq = chan->buffer_seq;
12348c2ecf20Sopenharmony_ci	l2cap_send_sframe(chan, &control);
12358c2ecf20Sopenharmony_ci}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_cistatic inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
12388c2ecf20Sopenharmony_ci{
12398c2ecf20Sopenharmony_ci	if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
12408c2ecf20Sopenharmony_ci		return true;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
12438c2ecf20Sopenharmony_ci}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_cistatic bool __amp_capable(struct l2cap_chan *chan)
12468c2ecf20Sopenharmony_ci{
12478c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
12488c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
12498c2ecf20Sopenharmony_ci	bool amp_available = false;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	if (!(conn->local_fixed_chan & L2CAP_FC_A2MP))
12528c2ecf20Sopenharmony_ci		return false;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	if (!(conn->remote_fixed_chan & L2CAP_FC_A2MP))
12558c2ecf20Sopenharmony_ci		return false;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	read_lock(&hci_dev_list_lock);
12588c2ecf20Sopenharmony_ci	list_for_each_entry(hdev, &hci_dev_list, list) {
12598c2ecf20Sopenharmony_ci		if (hdev->amp_type != AMP_TYPE_BREDR &&
12608c2ecf20Sopenharmony_ci		    test_bit(HCI_UP, &hdev->flags)) {
12618c2ecf20Sopenharmony_ci			amp_available = true;
12628c2ecf20Sopenharmony_ci			break;
12638c2ecf20Sopenharmony_ci		}
12648c2ecf20Sopenharmony_ci	}
12658c2ecf20Sopenharmony_ci	read_unlock(&hci_dev_list_lock);
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	if (chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED)
12688c2ecf20Sopenharmony_ci		return amp_available;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	return false;
12718c2ecf20Sopenharmony_ci}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_cistatic bool l2cap_check_efs(struct l2cap_chan *chan)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	/* Check EFS parameters */
12768c2ecf20Sopenharmony_ci	return true;
12778c2ecf20Sopenharmony_ci}
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_civoid l2cap_send_conn_req(struct l2cap_chan *chan)
12808c2ecf20Sopenharmony_ci{
12818c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
12828c2ecf20Sopenharmony_ci	struct l2cap_conn_req req;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	req.scid = cpu_to_le16(chan->scid);
12858c2ecf20Sopenharmony_ci	req.psm  = chan->psm;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	chan->ident = l2cap_get_ident(conn);
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	set_bit(CONF_CONNECT_PEND, &chan->conf_state);
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
12928c2ecf20Sopenharmony_ci}
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_cistatic void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 amp_id)
12958c2ecf20Sopenharmony_ci{
12968c2ecf20Sopenharmony_ci	struct l2cap_create_chan_req req;
12978c2ecf20Sopenharmony_ci	req.scid = cpu_to_le16(chan->scid);
12988c2ecf20Sopenharmony_ci	req.psm  = chan->psm;
12998c2ecf20Sopenharmony_ci	req.amp_id = amp_id;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	chan->ident = l2cap_get_ident(chan->conn);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ,
13048c2ecf20Sopenharmony_ci		       sizeof(req), &req);
13058c2ecf20Sopenharmony_ci}
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_cistatic void l2cap_move_setup(struct l2cap_chan *chan)
13088c2ecf20Sopenharmony_ci{
13098c2ecf20Sopenharmony_ci	struct sk_buff *skb;
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	if (chan->mode != L2CAP_MODE_ERTM)
13148c2ecf20Sopenharmony_ci		return;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	__clear_retrans_timer(chan);
13178c2ecf20Sopenharmony_ci	__clear_monitor_timer(chan);
13188c2ecf20Sopenharmony_ci	__clear_ack_timer(chan);
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	chan->retry_count = 0;
13218c2ecf20Sopenharmony_ci	skb_queue_walk(&chan->tx_q, skb) {
13228c2ecf20Sopenharmony_ci		if (bt_cb(skb)->l2cap.retries)
13238c2ecf20Sopenharmony_ci			bt_cb(skb)->l2cap.retries = 1;
13248c2ecf20Sopenharmony_ci		else
13258c2ecf20Sopenharmony_ci			break;
13268c2ecf20Sopenharmony_ci	}
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	chan->expected_tx_seq = chan->buffer_seq;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	clear_bit(CONN_REJ_ACT, &chan->conn_state);
13318c2ecf20Sopenharmony_ci	clear_bit(CONN_SREJ_ACT, &chan->conn_state);
13328c2ecf20Sopenharmony_ci	l2cap_seq_list_clear(&chan->retrans_list);
13338c2ecf20Sopenharmony_ci	l2cap_seq_list_clear(&chan->srej_list);
13348c2ecf20Sopenharmony_ci	skb_queue_purge(&chan->srej_q);
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	chan->tx_state = L2CAP_TX_STATE_XMIT;
13378c2ecf20Sopenharmony_ci	chan->rx_state = L2CAP_RX_STATE_MOVE;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
13408c2ecf20Sopenharmony_ci}
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_cistatic void l2cap_move_done(struct l2cap_chan *chan)
13438c2ecf20Sopenharmony_ci{
13448c2ecf20Sopenharmony_ci	u8 move_role = chan->move_role;
13458c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	chan->move_state = L2CAP_MOVE_STABLE;
13488c2ecf20Sopenharmony_ci	chan->move_role = L2CAP_MOVE_ROLE_NONE;
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	if (chan->mode != L2CAP_MODE_ERTM)
13518c2ecf20Sopenharmony_ci		return;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	switch (move_role) {
13548c2ecf20Sopenharmony_ci	case L2CAP_MOVE_ROLE_INITIATOR:
13558c2ecf20Sopenharmony_ci		l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL);
13568c2ecf20Sopenharmony_ci		chan->rx_state = L2CAP_RX_STATE_WAIT_F;
13578c2ecf20Sopenharmony_ci		break;
13588c2ecf20Sopenharmony_ci	case L2CAP_MOVE_ROLE_RESPONDER:
13598c2ecf20Sopenharmony_ci		chan->rx_state = L2CAP_RX_STATE_WAIT_P;
13608c2ecf20Sopenharmony_ci		break;
13618c2ecf20Sopenharmony_ci	}
13628c2ecf20Sopenharmony_ci}
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_cistatic void l2cap_chan_ready(struct l2cap_chan *chan)
13658c2ecf20Sopenharmony_ci{
13668c2ecf20Sopenharmony_ci	/* The channel may have already been flagged as connected in
13678c2ecf20Sopenharmony_ci	 * case of receiving data before the L2CAP info req/rsp
13688c2ecf20Sopenharmony_ci	 * procedure is complete.
13698c2ecf20Sopenharmony_ci	 */
13708c2ecf20Sopenharmony_ci	if (chan->state == BT_CONNECTED)
13718c2ecf20Sopenharmony_ci		return;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	/* This clears all conf flags, including CONF_NOT_COMPLETE */
13748c2ecf20Sopenharmony_ci	chan->conf_state = 0;
13758c2ecf20Sopenharmony_ci	__clear_chan_timer(chan);
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	switch (chan->mode) {
13788c2ecf20Sopenharmony_ci	case L2CAP_MODE_LE_FLOWCTL:
13798c2ecf20Sopenharmony_ci	case L2CAP_MODE_EXT_FLOWCTL:
13808c2ecf20Sopenharmony_ci		if (!chan->tx_credits)
13818c2ecf20Sopenharmony_ci			chan->ops->suspend(chan);
13828c2ecf20Sopenharmony_ci		break;
13838c2ecf20Sopenharmony_ci	}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	chan->state = BT_CONNECTED;
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	chan->ops->ready(chan);
13888c2ecf20Sopenharmony_ci}
13898c2ecf20Sopenharmony_ci
13908c2ecf20Sopenharmony_cistatic void l2cap_le_connect(struct l2cap_chan *chan)
13918c2ecf20Sopenharmony_ci{
13928c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
13938c2ecf20Sopenharmony_ci	struct l2cap_le_conn_req req;
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci	if (test_and_set_bit(FLAG_LE_CONN_REQ_SENT, &chan->flags))
13968c2ecf20Sopenharmony_ci		return;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	if (!chan->imtu)
13998c2ecf20Sopenharmony_ci		chan->imtu = chan->conn->mtu;
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	l2cap_le_flowctl_init(chan, 0);
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	req.psm     = chan->psm;
14048c2ecf20Sopenharmony_ci	req.scid    = cpu_to_le16(chan->scid);
14058c2ecf20Sopenharmony_ci	req.mtu     = cpu_to_le16(chan->imtu);
14068c2ecf20Sopenharmony_ci	req.mps     = cpu_to_le16(chan->mps);
14078c2ecf20Sopenharmony_ci	req.credits = cpu_to_le16(chan->rx_credits);
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	chan->ident = l2cap_get_ident(conn);
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_REQ,
14128c2ecf20Sopenharmony_ci		       sizeof(req), &req);
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_cistruct l2cap_ecred_conn_data {
14168c2ecf20Sopenharmony_ci	struct {
14178c2ecf20Sopenharmony_ci		struct l2cap_ecred_conn_req req;
14188c2ecf20Sopenharmony_ci		__le16 scid[5];
14198c2ecf20Sopenharmony_ci	} __packed pdu;
14208c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
14218c2ecf20Sopenharmony_ci	struct pid *pid;
14228c2ecf20Sopenharmony_ci	int count;
14238c2ecf20Sopenharmony_ci};
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_cistatic void l2cap_ecred_defer_connect(struct l2cap_chan *chan, void *data)
14268c2ecf20Sopenharmony_ci{
14278c2ecf20Sopenharmony_ci	struct l2cap_ecred_conn_data *conn = data;
14288c2ecf20Sopenharmony_ci	struct pid *pid;
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	if (chan == conn->chan)
14318c2ecf20Sopenharmony_ci		return;
14328c2ecf20Sopenharmony_ci
14338c2ecf20Sopenharmony_ci	if (!test_and_clear_bit(FLAG_DEFER_SETUP, &chan->flags))
14348c2ecf20Sopenharmony_ci		return;
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	pid = chan->ops->get_peer_pid(chan);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	/* Only add deferred channels with the same PID/PSM */
14398c2ecf20Sopenharmony_ci	if (conn->pid != pid || chan->psm != conn->chan->psm || chan->ident ||
14408c2ecf20Sopenharmony_ci	    chan->mode != L2CAP_MODE_EXT_FLOWCTL || chan->state != BT_CONNECT)
14418c2ecf20Sopenharmony_ci		return;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	if (test_and_set_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
14448c2ecf20Sopenharmony_ci		return;
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	l2cap_ecred_init(chan, 0);
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	/* Set the same ident so we can match on the rsp */
14498c2ecf20Sopenharmony_ci	chan->ident = conn->chan->ident;
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	/* Include all channels deferred */
14528c2ecf20Sopenharmony_ci	conn->pdu.scid[conn->count] = cpu_to_le16(chan->scid);
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	conn->count++;
14558c2ecf20Sopenharmony_ci}
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_cistatic void l2cap_ecred_connect(struct l2cap_chan *chan)
14588c2ecf20Sopenharmony_ci{
14598c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
14608c2ecf20Sopenharmony_ci	struct l2cap_ecred_conn_data data;
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	if (test_bit(FLAG_DEFER_SETUP, &chan->flags))
14638c2ecf20Sopenharmony_ci		return;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	if (test_and_set_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
14668c2ecf20Sopenharmony_ci		return;
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	l2cap_ecred_init(chan, 0);
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	memset(&data, 0, sizeof(data));
14718c2ecf20Sopenharmony_ci	data.pdu.req.psm     = chan->psm;
14728c2ecf20Sopenharmony_ci	data.pdu.req.mtu     = cpu_to_le16(chan->imtu);
14738c2ecf20Sopenharmony_ci	data.pdu.req.mps     = cpu_to_le16(chan->mps);
14748c2ecf20Sopenharmony_ci	data.pdu.req.credits = cpu_to_le16(chan->rx_credits);
14758c2ecf20Sopenharmony_ci	data.pdu.scid[0]     = cpu_to_le16(chan->scid);
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	chan->ident = l2cap_get_ident(conn);
14788c2ecf20Sopenharmony_ci	data.pid = chan->ops->get_peer_pid(chan);
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	data.count = 1;
14818c2ecf20Sopenharmony_ci	data.chan = chan;
14828c2ecf20Sopenharmony_ci	data.pid = chan->ops->get_peer_pid(chan);
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	__l2cap_chan_list(conn, l2cap_ecred_defer_connect, &data);
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, chan->ident, L2CAP_ECRED_CONN_REQ,
14878c2ecf20Sopenharmony_ci		       sizeof(data.pdu.req) + data.count * sizeof(__le16),
14888c2ecf20Sopenharmony_ci		       &data.pdu);
14898c2ecf20Sopenharmony_ci}
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_cistatic void l2cap_le_start(struct l2cap_chan *chan)
14928c2ecf20Sopenharmony_ci{
14938c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	if (!smp_conn_security(conn->hcon, chan->sec_level))
14968c2ecf20Sopenharmony_ci		return;
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	if (!chan->psm) {
14998c2ecf20Sopenharmony_ci		l2cap_chan_ready(chan);
15008c2ecf20Sopenharmony_ci		return;
15018c2ecf20Sopenharmony_ci	}
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	if (chan->state == BT_CONNECT) {
15048c2ecf20Sopenharmony_ci		if (chan->mode == L2CAP_MODE_EXT_FLOWCTL)
15058c2ecf20Sopenharmony_ci			l2cap_ecred_connect(chan);
15068c2ecf20Sopenharmony_ci		else
15078c2ecf20Sopenharmony_ci			l2cap_le_connect(chan);
15088c2ecf20Sopenharmony_ci	}
15098c2ecf20Sopenharmony_ci}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_cistatic void l2cap_start_connection(struct l2cap_chan *chan)
15128c2ecf20Sopenharmony_ci{
15138c2ecf20Sopenharmony_ci	if (__amp_capable(chan)) {
15148c2ecf20Sopenharmony_ci		BT_DBG("chan %p AMP capable: discover AMPs", chan);
15158c2ecf20Sopenharmony_ci		a2mp_discover_amp(chan);
15168c2ecf20Sopenharmony_ci	} else if (chan->conn->hcon->type == LE_LINK) {
15178c2ecf20Sopenharmony_ci		l2cap_le_start(chan);
15188c2ecf20Sopenharmony_ci	} else {
15198c2ecf20Sopenharmony_ci		l2cap_send_conn_req(chan);
15208c2ecf20Sopenharmony_ci	}
15218c2ecf20Sopenharmony_ci}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_cistatic void l2cap_request_info(struct l2cap_conn *conn)
15248c2ecf20Sopenharmony_ci{
15258c2ecf20Sopenharmony_ci	struct l2cap_info_req req;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
15288c2ecf20Sopenharmony_ci		return;
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
15338c2ecf20Sopenharmony_ci	conn->info_ident = l2cap_get_ident(conn);
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ,
15388c2ecf20Sopenharmony_ci		       sizeof(req), &req);
15398c2ecf20Sopenharmony_ci}
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_cistatic bool l2cap_check_enc_key_size(struct hci_conn *hcon)
15428c2ecf20Sopenharmony_ci{
15438c2ecf20Sopenharmony_ci	/* The minimum encryption key size needs to be enforced by the
15448c2ecf20Sopenharmony_ci	 * host stack before establishing any L2CAP connections. The
15458c2ecf20Sopenharmony_ci	 * specification in theory allows a minimum of 1, but to align
15468c2ecf20Sopenharmony_ci	 * BR/EDR and LE transports, a minimum of 7 is chosen.
15478c2ecf20Sopenharmony_ci	 *
15488c2ecf20Sopenharmony_ci	 * This check might also be called for unencrypted connections
15498c2ecf20Sopenharmony_ci	 * that have no key size requirements. Ensure that the link is
15508c2ecf20Sopenharmony_ci	 * actually encrypted before enforcing a key size.
15518c2ecf20Sopenharmony_ci	 */
15528c2ecf20Sopenharmony_ci	return (!test_bit(HCI_CONN_ENCRYPT, &hcon->flags) ||
15538c2ecf20Sopenharmony_ci		hcon->enc_key_size >= hcon->hdev->min_enc_key_size);
15548c2ecf20Sopenharmony_ci}
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_cistatic void l2cap_do_start(struct l2cap_chan *chan)
15578c2ecf20Sopenharmony_ci{
15588c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	if (conn->hcon->type == LE_LINK) {
15618c2ecf20Sopenharmony_ci		l2cap_le_start(chan);
15628c2ecf20Sopenharmony_ci		return;
15638c2ecf20Sopenharmony_ci	}
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_ci	if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)) {
15668c2ecf20Sopenharmony_ci		l2cap_request_info(conn);
15678c2ecf20Sopenharmony_ci		return;
15688c2ecf20Sopenharmony_ci	}
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
15718c2ecf20Sopenharmony_ci		return;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	if (!l2cap_chan_check_security(chan, true) ||
15748c2ecf20Sopenharmony_ci	    !__l2cap_no_conn_pending(chan))
15758c2ecf20Sopenharmony_ci		return;
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	if (l2cap_check_enc_key_size(conn->hcon))
15788c2ecf20Sopenharmony_ci		l2cap_start_connection(chan);
15798c2ecf20Sopenharmony_ci	else
15808c2ecf20Sopenharmony_ci		__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
15818c2ecf20Sopenharmony_ci}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_cistatic inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
15848c2ecf20Sopenharmony_ci{
15858c2ecf20Sopenharmony_ci	u32 local_feat_mask = l2cap_feat_mask;
15868c2ecf20Sopenharmony_ci	if (!disable_ertm)
15878c2ecf20Sopenharmony_ci		local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	switch (mode) {
15908c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
15918c2ecf20Sopenharmony_ci		return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
15928c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
15938c2ecf20Sopenharmony_ci		return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
15948c2ecf20Sopenharmony_ci	default:
15958c2ecf20Sopenharmony_ci		return 0x00;
15968c2ecf20Sopenharmony_ci	}
15978c2ecf20Sopenharmony_ci}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_cistatic void l2cap_send_disconn_req(struct l2cap_chan *chan, int err)
16008c2ecf20Sopenharmony_ci{
16018c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
16028c2ecf20Sopenharmony_ci	struct l2cap_disconn_req req;
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	if (!conn)
16058c2ecf20Sopenharmony_ci		return;
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	if (chan->mode == L2CAP_MODE_ERTM && chan->state == BT_CONNECTED) {
16088c2ecf20Sopenharmony_ci		__clear_retrans_timer(chan);
16098c2ecf20Sopenharmony_ci		__clear_monitor_timer(chan);
16108c2ecf20Sopenharmony_ci		__clear_ack_timer(chan);
16118c2ecf20Sopenharmony_ci	}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	if (chan->scid == L2CAP_CID_A2MP) {
16148c2ecf20Sopenharmony_ci		l2cap_state_change(chan, BT_DISCONN);
16158c2ecf20Sopenharmony_ci		return;
16168c2ecf20Sopenharmony_ci	}
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci	req.dcid = cpu_to_le16(chan->dcid);
16198c2ecf20Sopenharmony_ci	req.scid = cpu_to_le16(chan->scid);
16208c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ,
16218c2ecf20Sopenharmony_ci		       sizeof(req), &req);
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	l2cap_state_change_and_error(chan, BT_DISCONN, err);
16248c2ecf20Sopenharmony_ci}
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci/* ---- L2CAP connections ---- */
16278c2ecf20Sopenharmony_cistatic void l2cap_conn_start(struct l2cap_conn *conn)
16288c2ecf20Sopenharmony_ci{
16298c2ecf20Sopenharmony_ci	struct l2cap_chan *chan, *tmp;
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci	BT_DBG("conn %p", conn);
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
16368c2ecf20Sopenharmony_ci		l2cap_chan_lock(chan);
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
16398c2ecf20Sopenharmony_ci			l2cap_chan_ready(chan);
16408c2ecf20Sopenharmony_ci			l2cap_chan_unlock(chan);
16418c2ecf20Sopenharmony_ci			continue;
16428c2ecf20Sopenharmony_ci		}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci		if (chan->state == BT_CONNECT) {
16458c2ecf20Sopenharmony_ci			if (!l2cap_chan_check_security(chan, true) ||
16468c2ecf20Sopenharmony_ci			    !__l2cap_no_conn_pending(chan)) {
16478c2ecf20Sopenharmony_ci				l2cap_chan_unlock(chan);
16488c2ecf20Sopenharmony_ci				continue;
16498c2ecf20Sopenharmony_ci			}
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci			if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
16528c2ecf20Sopenharmony_ci			    && test_bit(CONF_STATE2_DEVICE,
16538c2ecf20Sopenharmony_ci					&chan->conf_state)) {
16548c2ecf20Sopenharmony_ci				l2cap_chan_close(chan, ECONNRESET);
16558c2ecf20Sopenharmony_ci				l2cap_chan_unlock(chan);
16568c2ecf20Sopenharmony_ci				continue;
16578c2ecf20Sopenharmony_ci			}
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci			if (l2cap_check_enc_key_size(conn->hcon))
16608c2ecf20Sopenharmony_ci				l2cap_start_connection(chan);
16618c2ecf20Sopenharmony_ci			else
16628c2ecf20Sopenharmony_ci				l2cap_chan_close(chan, ECONNREFUSED);
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci		} else if (chan->state == BT_CONNECT2) {
16658c2ecf20Sopenharmony_ci			struct l2cap_conn_rsp rsp;
16668c2ecf20Sopenharmony_ci			char buf[128];
16678c2ecf20Sopenharmony_ci			rsp.scid = cpu_to_le16(chan->dcid);
16688c2ecf20Sopenharmony_ci			rsp.dcid = cpu_to_le16(chan->scid);
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci			if (l2cap_chan_check_security(chan, false)) {
16718c2ecf20Sopenharmony_ci				if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
16728c2ecf20Sopenharmony_ci					rsp.result = cpu_to_le16(L2CAP_CR_PEND);
16738c2ecf20Sopenharmony_ci					rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
16748c2ecf20Sopenharmony_ci					chan->ops->defer(chan);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci				} else {
16778c2ecf20Sopenharmony_ci					l2cap_state_change(chan, BT_CONFIG);
16788c2ecf20Sopenharmony_ci					rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
16798c2ecf20Sopenharmony_ci					rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
16808c2ecf20Sopenharmony_ci				}
16818c2ecf20Sopenharmony_ci			} else {
16828c2ecf20Sopenharmony_ci				rsp.result = cpu_to_le16(L2CAP_CR_PEND);
16838c2ecf20Sopenharmony_ci				rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
16848c2ecf20Sopenharmony_ci			}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
16878c2ecf20Sopenharmony_ci				       sizeof(rsp), &rsp);
16888c2ecf20Sopenharmony_ci
16898c2ecf20Sopenharmony_ci			if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
16908c2ecf20Sopenharmony_ci			    rsp.result != L2CAP_CR_SUCCESS) {
16918c2ecf20Sopenharmony_ci				l2cap_chan_unlock(chan);
16928c2ecf20Sopenharmony_ci				continue;
16938c2ecf20Sopenharmony_ci			}
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci			set_bit(CONF_REQ_SENT, &chan->conf_state);
16968c2ecf20Sopenharmony_ci			l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
16978c2ecf20Sopenharmony_ci				       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
16988c2ecf20Sopenharmony_ci			chan->num_conf_req++;
16998c2ecf20Sopenharmony_ci		}
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci		l2cap_chan_unlock(chan);
17028c2ecf20Sopenharmony_ci	}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
17058c2ecf20Sopenharmony_ci}
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_cistatic void l2cap_le_conn_ready(struct l2cap_conn *conn)
17088c2ecf20Sopenharmony_ci{
17098c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
17108c2ecf20Sopenharmony_ci	struct hci_dev *hdev = hcon->hdev;
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	BT_DBG("%s conn %p", hdev->name, conn);
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	/* For outgoing pairing which doesn't necessarily have an
17158c2ecf20Sopenharmony_ci	 * associated socket (e.g. mgmt_pair_device).
17168c2ecf20Sopenharmony_ci	 */
17178c2ecf20Sopenharmony_ci	if (hcon->out)
17188c2ecf20Sopenharmony_ci		smp_conn_security(hcon, hcon->pending_sec_level);
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	/* For LE peripheral connections, make sure the connection interval
17218c2ecf20Sopenharmony_ci	 * is in the range of the minimum and maximum interval that has
17228c2ecf20Sopenharmony_ci	 * been configured for this connection. If not, then trigger
17238c2ecf20Sopenharmony_ci	 * the connection update procedure.
17248c2ecf20Sopenharmony_ci	 */
17258c2ecf20Sopenharmony_ci	if (hcon->role == HCI_ROLE_SLAVE &&
17268c2ecf20Sopenharmony_ci	    (hcon->le_conn_interval < hcon->le_conn_min_interval ||
17278c2ecf20Sopenharmony_ci	     hcon->le_conn_interval > hcon->le_conn_max_interval)) {
17288c2ecf20Sopenharmony_ci		struct l2cap_conn_param_update_req req;
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci		req.min = cpu_to_le16(hcon->le_conn_min_interval);
17318c2ecf20Sopenharmony_ci		req.max = cpu_to_le16(hcon->le_conn_max_interval);
17328c2ecf20Sopenharmony_ci		req.latency = cpu_to_le16(hcon->le_conn_latency);
17338c2ecf20Sopenharmony_ci		req.to_multiplier = cpu_to_le16(hcon->le_supv_timeout);
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, l2cap_get_ident(conn),
17368c2ecf20Sopenharmony_ci			       L2CAP_CONN_PARAM_UPDATE_REQ, sizeof(req), &req);
17378c2ecf20Sopenharmony_ci	}
17388c2ecf20Sopenharmony_ci}
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_cistatic void l2cap_conn_ready(struct l2cap_conn *conn)
17418c2ecf20Sopenharmony_ci{
17428c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
17438c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	BT_DBG("conn %p", conn);
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	if (hcon->type == ACL_LINK)
17488c2ecf20Sopenharmony_ci		l2cap_request_info(conn);
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
17518c2ecf20Sopenharmony_ci
17528c2ecf20Sopenharmony_ci	list_for_each_entry(chan, &conn->chan_l, list) {
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci		l2cap_chan_lock(chan);
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci		if (chan->scid == L2CAP_CID_A2MP) {
17578c2ecf20Sopenharmony_ci			l2cap_chan_unlock(chan);
17588c2ecf20Sopenharmony_ci			continue;
17598c2ecf20Sopenharmony_ci		}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci		if (hcon->type == LE_LINK) {
17628c2ecf20Sopenharmony_ci			l2cap_le_start(chan);
17638c2ecf20Sopenharmony_ci		} else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
17648c2ecf20Sopenharmony_ci			if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
17658c2ecf20Sopenharmony_ci				l2cap_chan_ready(chan);
17668c2ecf20Sopenharmony_ci		} else if (chan->state == BT_CONNECT) {
17678c2ecf20Sopenharmony_ci			l2cap_do_start(chan);
17688c2ecf20Sopenharmony_ci		}
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci		l2cap_chan_unlock(chan);
17718c2ecf20Sopenharmony_ci	}
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	if (hcon->type == LE_LINK)
17768c2ecf20Sopenharmony_ci		l2cap_le_conn_ready(conn);
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	queue_work(hcon->hdev->workqueue, &conn->pending_rx_work);
17798c2ecf20Sopenharmony_ci}
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci/* Notify sockets that we cannot guaranty reliability anymore */
17828c2ecf20Sopenharmony_cistatic void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
17838c2ecf20Sopenharmony_ci{
17848c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	BT_DBG("conn %p", conn);
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_ci	list_for_each_entry(chan, &conn->chan_l, list) {
17918c2ecf20Sopenharmony_ci		if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
17928c2ecf20Sopenharmony_ci			l2cap_chan_set_err(chan, err);
17938c2ecf20Sopenharmony_ci	}
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
17968c2ecf20Sopenharmony_ci}
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_cistatic void l2cap_info_timeout(struct work_struct *work)
17998c2ecf20Sopenharmony_ci{
18008c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
18018c2ecf20Sopenharmony_ci					       info_timer.work);
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci	conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
18048c2ecf20Sopenharmony_ci	conn->info_ident = 0;
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	l2cap_conn_start(conn);
18078c2ecf20Sopenharmony_ci}
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_ci/*
18108c2ecf20Sopenharmony_ci * l2cap_user
18118c2ecf20Sopenharmony_ci * External modules can register l2cap_user objects on l2cap_conn. The ->probe
18128c2ecf20Sopenharmony_ci * callback is called during registration. The ->remove callback is called
18138c2ecf20Sopenharmony_ci * during unregistration.
18148c2ecf20Sopenharmony_ci * An l2cap_user object can either be explicitly unregistered or when the
18158c2ecf20Sopenharmony_ci * underlying l2cap_conn object is deleted. This guarantees that l2cap->hcon,
18168c2ecf20Sopenharmony_ci * l2cap->hchan, .. are valid as long as the remove callback hasn't been called.
18178c2ecf20Sopenharmony_ci * External modules must own a reference to the l2cap_conn object if they intend
18188c2ecf20Sopenharmony_ci * to call l2cap_unregister_user(). The l2cap_conn object might get destroyed at
18198c2ecf20Sopenharmony_ci * any time if they don't.
18208c2ecf20Sopenharmony_ci */
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ciint l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user)
18238c2ecf20Sopenharmony_ci{
18248c2ecf20Sopenharmony_ci	struct hci_dev *hdev = conn->hcon->hdev;
18258c2ecf20Sopenharmony_ci	int ret;
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_ci	/* We need to check whether l2cap_conn is registered. If it is not, we
18288c2ecf20Sopenharmony_ci	 * must not register the l2cap_user. l2cap_conn_del() is unregisters
18298c2ecf20Sopenharmony_ci	 * l2cap_conn objects, but doesn't provide its own locking. Instead, it
18308c2ecf20Sopenharmony_ci	 * relies on the parent hci_conn object to be locked. This itself relies
18318c2ecf20Sopenharmony_ci	 * on the hci_dev object to be locked. So we must lock the hci device
18328c2ecf20Sopenharmony_ci	 * here, too. */
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	if (!list_empty(&user->list)) {
18378c2ecf20Sopenharmony_ci		ret = -EINVAL;
18388c2ecf20Sopenharmony_ci		goto out_unlock;
18398c2ecf20Sopenharmony_ci	}
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	/* conn->hchan is NULL after l2cap_conn_del() was called */
18428c2ecf20Sopenharmony_ci	if (!conn->hchan) {
18438c2ecf20Sopenharmony_ci		ret = -ENODEV;
18448c2ecf20Sopenharmony_ci		goto out_unlock;
18458c2ecf20Sopenharmony_ci	}
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	ret = user->probe(conn, user);
18488c2ecf20Sopenharmony_ci	if (ret)
18498c2ecf20Sopenharmony_ci		goto out_unlock;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	list_add(&user->list, &conn->users);
18528c2ecf20Sopenharmony_ci	ret = 0;
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ciout_unlock:
18558c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
18568c2ecf20Sopenharmony_ci	return ret;
18578c2ecf20Sopenharmony_ci}
18588c2ecf20Sopenharmony_ciEXPORT_SYMBOL(l2cap_register_user);
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_civoid l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user)
18618c2ecf20Sopenharmony_ci{
18628c2ecf20Sopenharmony_ci	struct hci_dev *hdev = conn->hcon->hdev;
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	if (list_empty(&user->list))
18678c2ecf20Sopenharmony_ci		goto out_unlock;
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	list_del_init(&user->list);
18708c2ecf20Sopenharmony_ci	user->remove(conn, user);
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ciout_unlock:
18738c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
18748c2ecf20Sopenharmony_ci}
18758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(l2cap_unregister_user);
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_cistatic void l2cap_unregister_all_users(struct l2cap_conn *conn)
18788c2ecf20Sopenharmony_ci{
18798c2ecf20Sopenharmony_ci	struct l2cap_user *user;
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	while (!list_empty(&conn->users)) {
18828c2ecf20Sopenharmony_ci		user = list_first_entry(&conn->users, struct l2cap_user, list);
18838c2ecf20Sopenharmony_ci		list_del_init(&user->list);
18848c2ecf20Sopenharmony_ci		user->remove(conn, user);
18858c2ecf20Sopenharmony_ci	}
18868c2ecf20Sopenharmony_ci}
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_cistatic void l2cap_conn_del(struct hci_conn *hcon, int err)
18898c2ecf20Sopenharmony_ci{
18908c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = hcon->l2cap_data;
18918c2ecf20Sopenharmony_ci	struct l2cap_chan *chan, *l;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	if (!conn)
18948c2ecf20Sopenharmony_ci		return;
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	kfree_skb(conn->rx_skb);
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	skb_queue_purge(&conn->pending_rx);
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	/* We can not call flush_work(&conn->pending_rx_work) here since we
19038c2ecf20Sopenharmony_ci	 * might block if we are running on a worker from the same workqueue
19048c2ecf20Sopenharmony_ci	 * pending_rx_work is waiting on.
19058c2ecf20Sopenharmony_ci	 */
19068c2ecf20Sopenharmony_ci	if (work_pending(&conn->pending_rx_work))
19078c2ecf20Sopenharmony_ci		cancel_work_sync(&conn->pending_rx_work);
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	if (work_pending(&conn->id_addr_update_work))
19108c2ecf20Sopenharmony_ci		cancel_work_sync(&conn->id_addr_update_work);
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	l2cap_unregister_all_users(conn);
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci	/* Force the connection to be immediately dropped */
19158c2ecf20Sopenharmony_ci	hcon->disc_timeout = 0;
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	/* Kill channels */
19208c2ecf20Sopenharmony_ci	list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
19218c2ecf20Sopenharmony_ci		l2cap_chan_hold(chan);
19228c2ecf20Sopenharmony_ci		l2cap_chan_lock(chan);
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci		l2cap_chan_del(chan, err);
19258c2ecf20Sopenharmony_ci
19268c2ecf20Sopenharmony_ci		chan->ops->close(chan);
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci		l2cap_chan_unlock(chan);
19298c2ecf20Sopenharmony_ci		l2cap_chan_put(chan);
19308c2ecf20Sopenharmony_ci	}
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci	hci_chan_del(conn->hchan);
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
19378c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&conn->info_timer);
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	hcon->l2cap_data = NULL;
19408c2ecf20Sopenharmony_ci	conn->hchan = NULL;
19418c2ecf20Sopenharmony_ci	l2cap_conn_put(conn);
19428c2ecf20Sopenharmony_ci}
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_cistatic void l2cap_conn_free(struct kref *ref)
19458c2ecf20Sopenharmony_ci{
19468c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = container_of(ref, struct l2cap_conn, ref);
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	hci_conn_put(conn->hcon);
19498c2ecf20Sopenharmony_ci	kfree(conn);
19508c2ecf20Sopenharmony_ci}
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_cistruct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn)
19538c2ecf20Sopenharmony_ci{
19548c2ecf20Sopenharmony_ci	kref_get(&conn->ref);
19558c2ecf20Sopenharmony_ci	return conn;
19568c2ecf20Sopenharmony_ci}
19578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(l2cap_conn_get);
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_civoid l2cap_conn_put(struct l2cap_conn *conn)
19608c2ecf20Sopenharmony_ci{
19618c2ecf20Sopenharmony_ci	kref_put(&conn->ref, l2cap_conn_free);
19628c2ecf20Sopenharmony_ci}
19638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(l2cap_conn_put);
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci/* ---- Socket interface ---- */
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci/* Find socket with psm and source / destination bdaddr.
19688c2ecf20Sopenharmony_ci * Returns closest match.
19698c2ecf20Sopenharmony_ci */
19708c2ecf20Sopenharmony_cistatic struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
19718c2ecf20Sopenharmony_ci						   bdaddr_t *src,
19728c2ecf20Sopenharmony_ci						   bdaddr_t *dst,
19738c2ecf20Sopenharmony_ci						   u8 link_type)
19748c2ecf20Sopenharmony_ci{
19758c2ecf20Sopenharmony_ci	struct l2cap_chan *c, *tmp, *c1 = NULL;
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ci	read_lock(&chan_list_lock);
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci	list_for_each_entry_safe(c, tmp, &chan_list, global_l) {
19808c2ecf20Sopenharmony_ci		if (state && c->state != state)
19818c2ecf20Sopenharmony_ci			continue;
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci		if (link_type == ACL_LINK && c->src_type != BDADDR_BREDR)
19848c2ecf20Sopenharmony_ci			continue;
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci		if (link_type == LE_LINK && c->src_type == BDADDR_BREDR)
19878c2ecf20Sopenharmony_ci			continue;
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci		if (c->chan_type != L2CAP_CHAN_FIXED && c->psm == psm) {
19908c2ecf20Sopenharmony_ci			int src_match, dst_match;
19918c2ecf20Sopenharmony_ci			int src_any, dst_any;
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ci			/* Exact match. */
19948c2ecf20Sopenharmony_ci			src_match = !bacmp(&c->src, src);
19958c2ecf20Sopenharmony_ci			dst_match = !bacmp(&c->dst, dst);
19968c2ecf20Sopenharmony_ci			if (src_match && dst_match) {
19978c2ecf20Sopenharmony_ci				if (!l2cap_chan_hold_unless_zero(c))
19988c2ecf20Sopenharmony_ci					continue;
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci				read_unlock(&chan_list_lock);
20018c2ecf20Sopenharmony_ci				return c;
20028c2ecf20Sopenharmony_ci			}
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci			/* Closest match */
20058c2ecf20Sopenharmony_ci			src_any = !bacmp(&c->src, BDADDR_ANY);
20068c2ecf20Sopenharmony_ci			dst_any = !bacmp(&c->dst, BDADDR_ANY);
20078c2ecf20Sopenharmony_ci			if ((src_match && dst_any) || (src_any && dst_match) ||
20088c2ecf20Sopenharmony_ci			    (src_any && dst_any))
20098c2ecf20Sopenharmony_ci				c1 = c;
20108c2ecf20Sopenharmony_ci		}
20118c2ecf20Sopenharmony_ci	}
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ci	if (c1)
20148c2ecf20Sopenharmony_ci		c1 = l2cap_chan_hold_unless_zero(c1);
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	read_unlock(&chan_list_lock);
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	return c1;
20198c2ecf20Sopenharmony_ci}
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_cistatic void l2cap_monitor_timeout(struct work_struct *work)
20228c2ecf20Sopenharmony_ci{
20238c2ecf20Sopenharmony_ci	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
20248c2ecf20Sopenharmony_ci					       monitor_timer.work);
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_ci	l2cap_chan_lock(chan);
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci	if (!chan->conn) {
20318c2ecf20Sopenharmony_ci		l2cap_chan_unlock(chan);
20328c2ecf20Sopenharmony_ci		l2cap_chan_put(chan);
20338c2ecf20Sopenharmony_ci		return;
20348c2ecf20Sopenharmony_ci	}
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	l2cap_tx(chan, NULL, NULL, L2CAP_EV_MONITOR_TO);
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
20398c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
20408c2ecf20Sopenharmony_ci}
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_cistatic void l2cap_retrans_timeout(struct work_struct *work)
20438c2ecf20Sopenharmony_ci{
20448c2ecf20Sopenharmony_ci	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
20458c2ecf20Sopenharmony_ci					       retrans_timer.work);
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	l2cap_chan_lock(chan);
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	if (!chan->conn) {
20528c2ecf20Sopenharmony_ci		l2cap_chan_unlock(chan);
20538c2ecf20Sopenharmony_ci		l2cap_chan_put(chan);
20548c2ecf20Sopenharmony_ci		return;
20558c2ecf20Sopenharmony_ci	}
20568c2ecf20Sopenharmony_ci
20578c2ecf20Sopenharmony_ci	l2cap_tx(chan, NULL, NULL, L2CAP_EV_RETRANS_TO);
20588c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
20598c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
20608c2ecf20Sopenharmony_ci}
20618c2ecf20Sopenharmony_ci
20628c2ecf20Sopenharmony_cistatic void l2cap_streaming_send(struct l2cap_chan *chan,
20638c2ecf20Sopenharmony_ci				 struct sk_buff_head *skbs)
20648c2ecf20Sopenharmony_ci{
20658c2ecf20Sopenharmony_ci	struct sk_buff *skb;
20668c2ecf20Sopenharmony_ci	struct l2cap_ctrl *control;
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	BT_DBG("chan %p, skbs %p", chan, skbs);
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci	if (__chan_is_moving(chan))
20718c2ecf20Sopenharmony_ci		return;
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	skb_queue_splice_tail_init(skbs, &chan->tx_q);
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	while (!skb_queue_empty(&chan->tx_q)) {
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci		skb = skb_dequeue(&chan->tx_q);
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_ci		bt_cb(skb)->l2cap.retries = 1;
20808c2ecf20Sopenharmony_ci		control = &bt_cb(skb)->l2cap;
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci		control->reqseq = 0;
20838c2ecf20Sopenharmony_ci		control->txseq = chan->next_tx_seq;
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci		__pack_control(chan, control, skb);
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci		if (chan->fcs == L2CAP_FCS_CRC16) {
20888c2ecf20Sopenharmony_ci			u16 fcs = crc16(0, (u8 *) skb->data, skb->len);
20898c2ecf20Sopenharmony_ci			put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
20908c2ecf20Sopenharmony_ci		}
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci		l2cap_do_send(chan, skb);
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci		BT_DBG("Sent txseq %u", control->txseq);
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci		chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
20978c2ecf20Sopenharmony_ci		chan->frames_sent++;
20988c2ecf20Sopenharmony_ci	}
20998c2ecf20Sopenharmony_ci}
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_cistatic int l2cap_ertm_send(struct l2cap_chan *chan)
21028c2ecf20Sopenharmony_ci{
21038c2ecf20Sopenharmony_ci	struct sk_buff *skb, *tx_skb;
21048c2ecf20Sopenharmony_ci	struct l2cap_ctrl *control;
21058c2ecf20Sopenharmony_ci	int sent = 0;
21068c2ecf20Sopenharmony_ci
21078c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	if (chan->state != BT_CONNECTED)
21108c2ecf20Sopenharmony_ci		return -ENOTCONN;
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
21138c2ecf20Sopenharmony_ci		return 0;
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	if (__chan_is_moving(chan))
21168c2ecf20Sopenharmony_ci		return 0;
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	while (chan->tx_send_head &&
21198c2ecf20Sopenharmony_ci	       chan->unacked_frames < chan->remote_tx_win &&
21208c2ecf20Sopenharmony_ci	       chan->tx_state == L2CAP_TX_STATE_XMIT) {
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci		skb = chan->tx_send_head;
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci		bt_cb(skb)->l2cap.retries = 1;
21258c2ecf20Sopenharmony_ci		control = &bt_cb(skb)->l2cap;
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci		if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
21288c2ecf20Sopenharmony_ci			control->final = 1;
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci		control->reqseq = chan->buffer_seq;
21318c2ecf20Sopenharmony_ci		chan->last_acked_seq = chan->buffer_seq;
21328c2ecf20Sopenharmony_ci		control->txseq = chan->next_tx_seq;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci		__pack_control(chan, control, skb);
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci		if (chan->fcs == L2CAP_FCS_CRC16) {
21378c2ecf20Sopenharmony_ci			u16 fcs = crc16(0, (u8 *) skb->data, skb->len);
21388c2ecf20Sopenharmony_ci			put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
21398c2ecf20Sopenharmony_ci		}
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci		/* Clone after data has been modified. Data is assumed to be
21428c2ecf20Sopenharmony_ci		   read-only (for locking purposes) on cloned sk_buffs.
21438c2ecf20Sopenharmony_ci		 */
21448c2ecf20Sopenharmony_ci		tx_skb = skb_clone(skb, GFP_KERNEL);
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci		if (!tx_skb)
21478c2ecf20Sopenharmony_ci			break;
21488c2ecf20Sopenharmony_ci
21498c2ecf20Sopenharmony_ci		__set_retrans_timer(chan);
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci		chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
21528c2ecf20Sopenharmony_ci		chan->unacked_frames++;
21538c2ecf20Sopenharmony_ci		chan->frames_sent++;
21548c2ecf20Sopenharmony_ci		sent++;
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci		if (skb_queue_is_last(&chan->tx_q, skb))
21578c2ecf20Sopenharmony_ci			chan->tx_send_head = NULL;
21588c2ecf20Sopenharmony_ci		else
21598c2ecf20Sopenharmony_ci			chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci		l2cap_do_send(chan, tx_skb);
21628c2ecf20Sopenharmony_ci		BT_DBG("Sent txseq %u", control->txseq);
21638c2ecf20Sopenharmony_ci	}
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci	BT_DBG("Sent %d, %u unacked, %u in ERTM queue", sent,
21668c2ecf20Sopenharmony_ci	       chan->unacked_frames, skb_queue_len(&chan->tx_q));
21678c2ecf20Sopenharmony_ci
21688c2ecf20Sopenharmony_ci	return sent;
21698c2ecf20Sopenharmony_ci}
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_cistatic void l2cap_ertm_resend(struct l2cap_chan *chan)
21728c2ecf20Sopenharmony_ci{
21738c2ecf20Sopenharmony_ci	struct l2cap_ctrl control;
21748c2ecf20Sopenharmony_ci	struct sk_buff *skb;
21758c2ecf20Sopenharmony_ci	struct sk_buff *tx_skb;
21768c2ecf20Sopenharmony_ci	u16 seq;
21778c2ecf20Sopenharmony_ci
21788c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
21818c2ecf20Sopenharmony_ci		return;
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	if (__chan_is_moving(chan))
21848c2ecf20Sopenharmony_ci		return;
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci	while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) {
21878c2ecf20Sopenharmony_ci		seq = l2cap_seq_list_pop(&chan->retrans_list);
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci		skb = l2cap_ertm_seq_in_queue(&chan->tx_q, seq);
21908c2ecf20Sopenharmony_ci		if (!skb) {
21918c2ecf20Sopenharmony_ci			BT_DBG("Error: Can't retransmit seq %d, frame missing",
21928c2ecf20Sopenharmony_ci			       seq);
21938c2ecf20Sopenharmony_ci			continue;
21948c2ecf20Sopenharmony_ci		}
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci		bt_cb(skb)->l2cap.retries++;
21978c2ecf20Sopenharmony_ci		control = bt_cb(skb)->l2cap;
21988c2ecf20Sopenharmony_ci
21998c2ecf20Sopenharmony_ci		if (chan->max_tx != 0 &&
22008c2ecf20Sopenharmony_ci		    bt_cb(skb)->l2cap.retries > chan->max_tx) {
22018c2ecf20Sopenharmony_ci			BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
22028c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, ECONNRESET);
22038c2ecf20Sopenharmony_ci			l2cap_seq_list_clear(&chan->retrans_list);
22048c2ecf20Sopenharmony_ci			break;
22058c2ecf20Sopenharmony_ci		}
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci		control.reqseq = chan->buffer_seq;
22088c2ecf20Sopenharmony_ci		if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
22098c2ecf20Sopenharmony_ci			control.final = 1;
22108c2ecf20Sopenharmony_ci		else
22118c2ecf20Sopenharmony_ci			control.final = 0;
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci		if (skb_cloned(skb)) {
22148c2ecf20Sopenharmony_ci			/* Cloned sk_buffs are read-only, so we need a
22158c2ecf20Sopenharmony_ci			 * writeable copy
22168c2ecf20Sopenharmony_ci			 */
22178c2ecf20Sopenharmony_ci			tx_skb = skb_copy(skb, GFP_KERNEL);
22188c2ecf20Sopenharmony_ci		} else {
22198c2ecf20Sopenharmony_ci			tx_skb = skb_clone(skb, GFP_KERNEL);
22208c2ecf20Sopenharmony_ci		}
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci		if (!tx_skb) {
22238c2ecf20Sopenharmony_ci			l2cap_seq_list_clear(&chan->retrans_list);
22248c2ecf20Sopenharmony_ci			break;
22258c2ecf20Sopenharmony_ci		}
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci		/* Update skb contents */
22288c2ecf20Sopenharmony_ci		if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
22298c2ecf20Sopenharmony_ci			put_unaligned_le32(__pack_extended_control(&control),
22308c2ecf20Sopenharmony_ci					   tx_skb->data + L2CAP_HDR_SIZE);
22318c2ecf20Sopenharmony_ci		} else {
22328c2ecf20Sopenharmony_ci			put_unaligned_le16(__pack_enhanced_control(&control),
22338c2ecf20Sopenharmony_ci					   tx_skb->data + L2CAP_HDR_SIZE);
22348c2ecf20Sopenharmony_ci		}
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci		/* Update FCS */
22378c2ecf20Sopenharmony_ci		if (chan->fcs == L2CAP_FCS_CRC16) {
22388c2ecf20Sopenharmony_ci			u16 fcs = crc16(0, (u8 *) tx_skb->data,
22398c2ecf20Sopenharmony_ci					tx_skb->len - L2CAP_FCS_SIZE);
22408c2ecf20Sopenharmony_ci			put_unaligned_le16(fcs, skb_tail_pointer(tx_skb) -
22418c2ecf20Sopenharmony_ci						L2CAP_FCS_SIZE);
22428c2ecf20Sopenharmony_ci		}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci		l2cap_do_send(chan, tx_skb);
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_ci		BT_DBG("Resent txseq %d", control.txseq);
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci		chan->last_acked_seq = chan->buffer_seq;
22498c2ecf20Sopenharmony_ci	}
22508c2ecf20Sopenharmony_ci}
22518c2ecf20Sopenharmony_ci
22528c2ecf20Sopenharmony_cistatic void l2cap_retransmit(struct l2cap_chan *chan,
22538c2ecf20Sopenharmony_ci			     struct l2cap_ctrl *control)
22548c2ecf20Sopenharmony_ci{
22558c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p", chan, control);
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	l2cap_seq_list_append(&chan->retrans_list, control->reqseq);
22588c2ecf20Sopenharmony_ci	l2cap_ertm_resend(chan);
22598c2ecf20Sopenharmony_ci}
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_cistatic void l2cap_retransmit_all(struct l2cap_chan *chan,
22628c2ecf20Sopenharmony_ci				 struct l2cap_ctrl *control)
22638c2ecf20Sopenharmony_ci{
22648c2ecf20Sopenharmony_ci	struct sk_buff *skb;
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p", chan, control);
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci	if (control->poll)
22698c2ecf20Sopenharmony_ci		set_bit(CONN_SEND_FBIT, &chan->conn_state);
22708c2ecf20Sopenharmony_ci
22718c2ecf20Sopenharmony_ci	l2cap_seq_list_clear(&chan->retrans_list);
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
22748c2ecf20Sopenharmony_ci		return;
22758c2ecf20Sopenharmony_ci
22768c2ecf20Sopenharmony_ci	if (chan->unacked_frames) {
22778c2ecf20Sopenharmony_ci		skb_queue_walk(&chan->tx_q, skb) {
22788c2ecf20Sopenharmony_ci			if (bt_cb(skb)->l2cap.txseq == control->reqseq ||
22798c2ecf20Sopenharmony_ci			    skb == chan->tx_send_head)
22808c2ecf20Sopenharmony_ci				break;
22818c2ecf20Sopenharmony_ci		}
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci		skb_queue_walk_from(&chan->tx_q, skb) {
22848c2ecf20Sopenharmony_ci			if (skb == chan->tx_send_head)
22858c2ecf20Sopenharmony_ci				break;
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci			l2cap_seq_list_append(&chan->retrans_list,
22888c2ecf20Sopenharmony_ci					      bt_cb(skb)->l2cap.txseq);
22898c2ecf20Sopenharmony_ci		}
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci		l2cap_ertm_resend(chan);
22928c2ecf20Sopenharmony_ci	}
22938c2ecf20Sopenharmony_ci}
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_cistatic void l2cap_send_ack(struct l2cap_chan *chan)
22968c2ecf20Sopenharmony_ci{
22978c2ecf20Sopenharmony_ci	struct l2cap_ctrl control;
22988c2ecf20Sopenharmony_ci	u16 frames_to_ack = __seq_offset(chan, chan->buffer_seq,
22998c2ecf20Sopenharmony_ci					 chan->last_acked_seq);
23008c2ecf20Sopenharmony_ci	int threshold;
23018c2ecf20Sopenharmony_ci
23028c2ecf20Sopenharmony_ci	BT_DBG("chan %p last_acked_seq %d buffer_seq %d",
23038c2ecf20Sopenharmony_ci	       chan, chan->last_acked_seq, chan->buffer_seq);
23048c2ecf20Sopenharmony_ci
23058c2ecf20Sopenharmony_ci	memset(&control, 0, sizeof(control));
23068c2ecf20Sopenharmony_ci	control.sframe = 1;
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
23098c2ecf20Sopenharmony_ci	    chan->rx_state == L2CAP_RX_STATE_RECV) {
23108c2ecf20Sopenharmony_ci		__clear_ack_timer(chan);
23118c2ecf20Sopenharmony_ci		control.super = L2CAP_SUPER_RNR;
23128c2ecf20Sopenharmony_ci		control.reqseq = chan->buffer_seq;
23138c2ecf20Sopenharmony_ci		l2cap_send_sframe(chan, &control);
23148c2ecf20Sopenharmony_ci	} else {
23158c2ecf20Sopenharmony_ci		if (!test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) {
23168c2ecf20Sopenharmony_ci			l2cap_ertm_send(chan);
23178c2ecf20Sopenharmony_ci			/* If any i-frames were sent, they included an ack */
23188c2ecf20Sopenharmony_ci			if (chan->buffer_seq == chan->last_acked_seq)
23198c2ecf20Sopenharmony_ci				frames_to_ack = 0;
23208c2ecf20Sopenharmony_ci		}
23218c2ecf20Sopenharmony_ci
23228c2ecf20Sopenharmony_ci		/* Ack now if the window is 3/4ths full.
23238c2ecf20Sopenharmony_ci		 * Calculate without mul or div
23248c2ecf20Sopenharmony_ci		 */
23258c2ecf20Sopenharmony_ci		threshold = chan->ack_win;
23268c2ecf20Sopenharmony_ci		threshold += threshold << 1;
23278c2ecf20Sopenharmony_ci		threshold >>= 2;
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci		BT_DBG("frames_to_ack %u, threshold %d", frames_to_ack,
23308c2ecf20Sopenharmony_ci		       threshold);
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci		if (frames_to_ack >= threshold) {
23338c2ecf20Sopenharmony_ci			__clear_ack_timer(chan);
23348c2ecf20Sopenharmony_ci			control.super = L2CAP_SUPER_RR;
23358c2ecf20Sopenharmony_ci			control.reqseq = chan->buffer_seq;
23368c2ecf20Sopenharmony_ci			l2cap_send_sframe(chan, &control);
23378c2ecf20Sopenharmony_ci			frames_to_ack = 0;
23388c2ecf20Sopenharmony_ci		}
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci		if (frames_to_ack)
23418c2ecf20Sopenharmony_ci			__set_ack_timer(chan);
23428c2ecf20Sopenharmony_ci	}
23438c2ecf20Sopenharmony_ci}
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_cistatic inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
23468c2ecf20Sopenharmony_ci					 struct msghdr *msg, int len,
23478c2ecf20Sopenharmony_ci					 int count, struct sk_buff *skb)
23488c2ecf20Sopenharmony_ci{
23498c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
23508c2ecf20Sopenharmony_ci	struct sk_buff **frag;
23518c2ecf20Sopenharmony_ci	int sent = 0;
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci	if (!copy_from_iter_full(skb_put(skb, count), count, &msg->msg_iter))
23548c2ecf20Sopenharmony_ci		return -EFAULT;
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci	sent += count;
23578c2ecf20Sopenharmony_ci	len  -= count;
23588c2ecf20Sopenharmony_ci
23598c2ecf20Sopenharmony_ci	/* Continuation fragments (no L2CAP header) */
23608c2ecf20Sopenharmony_ci	frag = &skb_shinfo(skb)->frag_list;
23618c2ecf20Sopenharmony_ci	while (len) {
23628c2ecf20Sopenharmony_ci		struct sk_buff *tmp;
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ci		count = min_t(unsigned int, conn->mtu, len);
23658c2ecf20Sopenharmony_ci
23668c2ecf20Sopenharmony_ci		tmp = chan->ops->alloc_skb(chan, 0, count,
23678c2ecf20Sopenharmony_ci					   msg->msg_flags & MSG_DONTWAIT);
23688c2ecf20Sopenharmony_ci		if (IS_ERR(tmp))
23698c2ecf20Sopenharmony_ci			return PTR_ERR(tmp);
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci		*frag = tmp;
23728c2ecf20Sopenharmony_ci
23738c2ecf20Sopenharmony_ci		if (!copy_from_iter_full(skb_put(*frag, count), count,
23748c2ecf20Sopenharmony_ci				   &msg->msg_iter))
23758c2ecf20Sopenharmony_ci			return -EFAULT;
23768c2ecf20Sopenharmony_ci
23778c2ecf20Sopenharmony_ci		sent += count;
23788c2ecf20Sopenharmony_ci		len  -= count;
23798c2ecf20Sopenharmony_ci
23808c2ecf20Sopenharmony_ci		skb->len += (*frag)->len;
23818c2ecf20Sopenharmony_ci		skb->data_len += (*frag)->len;
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci		frag = &(*frag)->next;
23848c2ecf20Sopenharmony_ci	}
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	return sent;
23878c2ecf20Sopenharmony_ci}
23888c2ecf20Sopenharmony_ci
23898c2ecf20Sopenharmony_cistatic struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
23908c2ecf20Sopenharmony_ci						 struct msghdr *msg, size_t len)
23918c2ecf20Sopenharmony_ci{
23928c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
23938c2ecf20Sopenharmony_ci	struct sk_buff *skb;
23948c2ecf20Sopenharmony_ci	int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
23958c2ecf20Sopenharmony_ci	struct l2cap_hdr *lh;
23968c2ecf20Sopenharmony_ci
23978c2ecf20Sopenharmony_ci	BT_DBG("chan %p psm 0x%2.2x len %zu", chan,
23988c2ecf20Sopenharmony_ci	       __le16_to_cpu(chan->psm), len);
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_ci	count = min_t(unsigned int, (conn->mtu - hlen), len);
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	skb = chan->ops->alloc_skb(chan, hlen, count,
24038c2ecf20Sopenharmony_ci				   msg->msg_flags & MSG_DONTWAIT);
24048c2ecf20Sopenharmony_ci	if (IS_ERR(skb))
24058c2ecf20Sopenharmony_ci		return skb;
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci	/* Create L2CAP header */
24088c2ecf20Sopenharmony_ci	lh = skb_put(skb, L2CAP_HDR_SIZE);
24098c2ecf20Sopenharmony_ci	lh->cid = cpu_to_le16(chan->dcid);
24108c2ecf20Sopenharmony_ci	lh->len = cpu_to_le16(len + L2CAP_PSMLEN_SIZE);
24118c2ecf20Sopenharmony_ci	put_unaligned(chan->psm, (__le16 *) skb_put(skb, L2CAP_PSMLEN_SIZE));
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_ci	err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
24148c2ecf20Sopenharmony_ci	if (unlikely(err < 0)) {
24158c2ecf20Sopenharmony_ci		kfree_skb(skb);
24168c2ecf20Sopenharmony_ci		return ERR_PTR(err);
24178c2ecf20Sopenharmony_ci	}
24188c2ecf20Sopenharmony_ci	return skb;
24198c2ecf20Sopenharmony_ci}
24208c2ecf20Sopenharmony_ci
24218c2ecf20Sopenharmony_cistatic struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
24228c2ecf20Sopenharmony_ci					      struct msghdr *msg, size_t len)
24238c2ecf20Sopenharmony_ci{
24248c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
24258c2ecf20Sopenharmony_ci	struct sk_buff *skb;
24268c2ecf20Sopenharmony_ci	int err, count;
24278c2ecf20Sopenharmony_ci	struct l2cap_hdr *lh;
24288c2ecf20Sopenharmony_ci
24298c2ecf20Sopenharmony_ci	BT_DBG("chan %p len %zu", chan, len);
24308c2ecf20Sopenharmony_ci
24318c2ecf20Sopenharmony_ci	count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len);
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_ci	skb = chan->ops->alloc_skb(chan, L2CAP_HDR_SIZE, count,
24348c2ecf20Sopenharmony_ci				   msg->msg_flags & MSG_DONTWAIT);
24358c2ecf20Sopenharmony_ci	if (IS_ERR(skb))
24368c2ecf20Sopenharmony_ci		return skb;
24378c2ecf20Sopenharmony_ci
24388c2ecf20Sopenharmony_ci	/* Create L2CAP header */
24398c2ecf20Sopenharmony_ci	lh = skb_put(skb, L2CAP_HDR_SIZE);
24408c2ecf20Sopenharmony_ci	lh->cid = cpu_to_le16(chan->dcid);
24418c2ecf20Sopenharmony_ci	lh->len = cpu_to_le16(len);
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci	err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
24448c2ecf20Sopenharmony_ci	if (unlikely(err < 0)) {
24458c2ecf20Sopenharmony_ci		kfree_skb(skb);
24468c2ecf20Sopenharmony_ci		return ERR_PTR(err);
24478c2ecf20Sopenharmony_ci	}
24488c2ecf20Sopenharmony_ci	return skb;
24498c2ecf20Sopenharmony_ci}
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_cistatic struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
24528c2ecf20Sopenharmony_ci					       struct msghdr *msg, size_t len,
24538c2ecf20Sopenharmony_ci					       u16 sdulen)
24548c2ecf20Sopenharmony_ci{
24558c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
24568c2ecf20Sopenharmony_ci	struct sk_buff *skb;
24578c2ecf20Sopenharmony_ci	int err, count, hlen;
24588c2ecf20Sopenharmony_ci	struct l2cap_hdr *lh;
24598c2ecf20Sopenharmony_ci
24608c2ecf20Sopenharmony_ci	BT_DBG("chan %p len %zu", chan, len);
24618c2ecf20Sopenharmony_ci
24628c2ecf20Sopenharmony_ci	if (!conn)
24638c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOTCONN);
24648c2ecf20Sopenharmony_ci
24658c2ecf20Sopenharmony_ci	hlen = __ertm_hdr_size(chan);
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	if (sdulen)
24688c2ecf20Sopenharmony_ci		hlen += L2CAP_SDULEN_SIZE;
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci	if (chan->fcs == L2CAP_FCS_CRC16)
24718c2ecf20Sopenharmony_ci		hlen += L2CAP_FCS_SIZE;
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_ci	count = min_t(unsigned int, (conn->mtu - hlen), len);
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci	skb = chan->ops->alloc_skb(chan, hlen, count,
24768c2ecf20Sopenharmony_ci				   msg->msg_flags & MSG_DONTWAIT);
24778c2ecf20Sopenharmony_ci	if (IS_ERR(skb))
24788c2ecf20Sopenharmony_ci		return skb;
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci	/* Create L2CAP header */
24818c2ecf20Sopenharmony_ci	lh = skb_put(skb, L2CAP_HDR_SIZE);
24828c2ecf20Sopenharmony_ci	lh->cid = cpu_to_le16(chan->dcid);
24838c2ecf20Sopenharmony_ci	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
24848c2ecf20Sopenharmony_ci
24858c2ecf20Sopenharmony_ci	/* Control header is populated later */
24868c2ecf20Sopenharmony_ci	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
24878c2ecf20Sopenharmony_ci		put_unaligned_le32(0, skb_put(skb, L2CAP_EXT_CTRL_SIZE));
24888c2ecf20Sopenharmony_ci	else
24898c2ecf20Sopenharmony_ci		put_unaligned_le16(0, skb_put(skb, L2CAP_ENH_CTRL_SIZE));
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_ci	if (sdulen)
24928c2ecf20Sopenharmony_ci		put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
24958c2ecf20Sopenharmony_ci	if (unlikely(err < 0)) {
24968c2ecf20Sopenharmony_ci		kfree_skb(skb);
24978c2ecf20Sopenharmony_ci		return ERR_PTR(err);
24988c2ecf20Sopenharmony_ci	}
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci	bt_cb(skb)->l2cap.fcs = chan->fcs;
25018c2ecf20Sopenharmony_ci	bt_cb(skb)->l2cap.retries = 0;
25028c2ecf20Sopenharmony_ci	return skb;
25038c2ecf20Sopenharmony_ci}
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_cistatic int l2cap_segment_sdu(struct l2cap_chan *chan,
25068c2ecf20Sopenharmony_ci			     struct sk_buff_head *seg_queue,
25078c2ecf20Sopenharmony_ci			     struct msghdr *msg, size_t len)
25088c2ecf20Sopenharmony_ci{
25098c2ecf20Sopenharmony_ci	struct sk_buff *skb;
25108c2ecf20Sopenharmony_ci	u16 sdu_len;
25118c2ecf20Sopenharmony_ci	size_t pdu_len;
25128c2ecf20Sopenharmony_ci	u8 sar;
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_ci	BT_DBG("chan %p, msg %p, len %zu", chan, msg, len);
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_ci	/* It is critical that ERTM PDUs fit in a single HCI fragment,
25178c2ecf20Sopenharmony_ci	 * so fragmented skbs are not used.  The HCI layer's handling
25188c2ecf20Sopenharmony_ci	 * of fragmented skbs is not compatible with ERTM's queueing.
25198c2ecf20Sopenharmony_ci	 */
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	/* PDU size is derived from the HCI MTU */
25228c2ecf20Sopenharmony_ci	pdu_len = chan->conn->mtu;
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci	/* Constrain PDU size for BR/EDR connections */
25258c2ecf20Sopenharmony_ci	if (!chan->hs_hcon)
25268c2ecf20Sopenharmony_ci		pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci	/* Adjust for largest possible L2CAP overhead. */
25298c2ecf20Sopenharmony_ci	if (chan->fcs)
25308c2ecf20Sopenharmony_ci		pdu_len -= L2CAP_FCS_SIZE;
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci	pdu_len -= __ertm_hdr_size(chan);
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci	/* Remote device may have requested smaller PDUs */
25358c2ecf20Sopenharmony_ci	pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci	if (len <= pdu_len) {
25388c2ecf20Sopenharmony_ci		sar = L2CAP_SAR_UNSEGMENTED;
25398c2ecf20Sopenharmony_ci		sdu_len = 0;
25408c2ecf20Sopenharmony_ci		pdu_len = len;
25418c2ecf20Sopenharmony_ci	} else {
25428c2ecf20Sopenharmony_ci		sar = L2CAP_SAR_START;
25438c2ecf20Sopenharmony_ci		sdu_len = len;
25448c2ecf20Sopenharmony_ci	}
25458c2ecf20Sopenharmony_ci
25468c2ecf20Sopenharmony_ci	while (len > 0) {
25478c2ecf20Sopenharmony_ci		skb = l2cap_create_iframe_pdu(chan, msg, pdu_len, sdu_len);
25488c2ecf20Sopenharmony_ci
25498c2ecf20Sopenharmony_ci		if (IS_ERR(skb)) {
25508c2ecf20Sopenharmony_ci			__skb_queue_purge(seg_queue);
25518c2ecf20Sopenharmony_ci			return PTR_ERR(skb);
25528c2ecf20Sopenharmony_ci		}
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci		bt_cb(skb)->l2cap.sar = sar;
25558c2ecf20Sopenharmony_ci		__skb_queue_tail(seg_queue, skb);
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci		len -= pdu_len;
25588c2ecf20Sopenharmony_ci		if (sdu_len)
25598c2ecf20Sopenharmony_ci			sdu_len = 0;
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci		if (len <= pdu_len) {
25628c2ecf20Sopenharmony_ci			sar = L2CAP_SAR_END;
25638c2ecf20Sopenharmony_ci			pdu_len = len;
25648c2ecf20Sopenharmony_ci		} else {
25658c2ecf20Sopenharmony_ci			sar = L2CAP_SAR_CONTINUE;
25668c2ecf20Sopenharmony_ci		}
25678c2ecf20Sopenharmony_ci	}
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci	return 0;
25708c2ecf20Sopenharmony_ci}
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_cistatic struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan,
25738c2ecf20Sopenharmony_ci						   struct msghdr *msg,
25748c2ecf20Sopenharmony_ci						   size_t len, u16 sdulen)
25758c2ecf20Sopenharmony_ci{
25768c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
25778c2ecf20Sopenharmony_ci	struct sk_buff *skb;
25788c2ecf20Sopenharmony_ci	int err, count, hlen;
25798c2ecf20Sopenharmony_ci	struct l2cap_hdr *lh;
25808c2ecf20Sopenharmony_ci
25818c2ecf20Sopenharmony_ci	BT_DBG("chan %p len %zu", chan, len);
25828c2ecf20Sopenharmony_ci
25838c2ecf20Sopenharmony_ci	if (!conn)
25848c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOTCONN);
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_ci	hlen = L2CAP_HDR_SIZE;
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci	if (sdulen)
25898c2ecf20Sopenharmony_ci		hlen += L2CAP_SDULEN_SIZE;
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci	count = min_t(unsigned int, (conn->mtu - hlen), len);
25928c2ecf20Sopenharmony_ci
25938c2ecf20Sopenharmony_ci	skb = chan->ops->alloc_skb(chan, hlen, count,
25948c2ecf20Sopenharmony_ci				   msg->msg_flags & MSG_DONTWAIT);
25958c2ecf20Sopenharmony_ci	if (IS_ERR(skb))
25968c2ecf20Sopenharmony_ci		return skb;
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci	/* Create L2CAP header */
25998c2ecf20Sopenharmony_ci	lh = skb_put(skb, L2CAP_HDR_SIZE);
26008c2ecf20Sopenharmony_ci	lh->cid = cpu_to_le16(chan->dcid);
26018c2ecf20Sopenharmony_ci	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci	if (sdulen)
26048c2ecf20Sopenharmony_ci		put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
26078c2ecf20Sopenharmony_ci	if (unlikely(err < 0)) {
26088c2ecf20Sopenharmony_ci		kfree_skb(skb);
26098c2ecf20Sopenharmony_ci		return ERR_PTR(err);
26108c2ecf20Sopenharmony_ci	}
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	return skb;
26138c2ecf20Sopenharmony_ci}
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_cistatic int l2cap_segment_le_sdu(struct l2cap_chan *chan,
26168c2ecf20Sopenharmony_ci				struct sk_buff_head *seg_queue,
26178c2ecf20Sopenharmony_ci				struct msghdr *msg, size_t len)
26188c2ecf20Sopenharmony_ci{
26198c2ecf20Sopenharmony_ci	struct sk_buff *skb;
26208c2ecf20Sopenharmony_ci	size_t pdu_len;
26218c2ecf20Sopenharmony_ci	u16 sdu_len;
26228c2ecf20Sopenharmony_ci
26238c2ecf20Sopenharmony_ci	BT_DBG("chan %p, msg %p, len %zu", chan, msg, len);
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	sdu_len = len;
26268c2ecf20Sopenharmony_ci	pdu_len = chan->remote_mps - L2CAP_SDULEN_SIZE;
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci	while (len > 0) {
26298c2ecf20Sopenharmony_ci		if (len <= pdu_len)
26308c2ecf20Sopenharmony_ci			pdu_len = len;
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci		skb = l2cap_create_le_flowctl_pdu(chan, msg, pdu_len, sdu_len);
26338c2ecf20Sopenharmony_ci		if (IS_ERR(skb)) {
26348c2ecf20Sopenharmony_ci			__skb_queue_purge(seg_queue);
26358c2ecf20Sopenharmony_ci			return PTR_ERR(skb);
26368c2ecf20Sopenharmony_ci		}
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci		__skb_queue_tail(seg_queue, skb);
26398c2ecf20Sopenharmony_ci
26408c2ecf20Sopenharmony_ci		len -= pdu_len;
26418c2ecf20Sopenharmony_ci
26428c2ecf20Sopenharmony_ci		if (sdu_len) {
26438c2ecf20Sopenharmony_ci			sdu_len = 0;
26448c2ecf20Sopenharmony_ci			pdu_len += L2CAP_SDULEN_SIZE;
26458c2ecf20Sopenharmony_ci		}
26468c2ecf20Sopenharmony_ci	}
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	return 0;
26498c2ecf20Sopenharmony_ci}
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_cistatic void l2cap_le_flowctl_send(struct l2cap_chan *chan)
26528c2ecf20Sopenharmony_ci{
26538c2ecf20Sopenharmony_ci	int sent = 0;
26548c2ecf20Sopenharmony_ci
26558c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ci	while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) {
26588c2ecf20Sopenharmony_ci		l2cap_do_send(chan, skb_dequeue(&chan->tx_q));
26598c2ecf20Sopenharmony_ci		chan->tx_credits--;
26608c2ecf20Sopenharmony_ci		sent++;
26618c2ecf20Sopenharmony_ci	}
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci	BT_DBG("Sent %d credits %u queued %u", sent, chan->tx_credits,
26648c2ecf20Sopenharmony_ci	       skb_queue_len(&chan->tx_q));
26658c2ecf20Sopenharmony_ci}
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ciint l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
26688c2ecf20Sopenharmony_ci{
26698c2ecf20Sopenharmony_ci	struct sk_buff *skb;
26708c2ecf20Sopenharmony_ci	int err;
26718c2ecf20Sopenharmony_ci	struct sk_buff_head seg_queue;
26728c2ecf20Sopenharmony_ci
26738c2ecf20Sopenharmony_ci	if (!chan->conn)
26748c2ecf20Sopenharmony_ci		return -ENOTCONN;
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	/* Connectionless channel */
26778c2ecf20Sopenharmony_ci	if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
26788c2ecf20Sopenharmony_ci		skb = l2cap_create_connless_pdu(chan, msg, len);
26798c2ecf20Sopenharmony_ci		if (IS_ERR(skb))
26808c2ecf20Sopenharmony_ci			return PTR_ERR(skb);
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_ci		l2cap_do_send(chan, skb);
26838c2ecf20Sopenharmony_ci		return len;
26848c2ecf20Sopenharmony_ci	}
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_ci	switch (chan->mode) {
26878c2ecf20Sopenharmony_ci	case L2CAP_MODE_LE_FLOWCTL:
26888c2ecf20Sopenharmony_ci	case L2CAP_MODE_EXT_FLOWCTL:
26898c2ecf20Sopenharmony_ci		/* Check outgoing MTU */
26908c2ecf20Sopenharmony_ci		if (len > chan->omtu)
26918c2ecf20Sopenharmony_ci			return -EMSGSIZE;
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_ci		__skb_queue_head_init(&seg_queue);
26948c2ecf20Sopenharmony_ci
26958c2ecf20Sopenharmony_ci		err = l2cap_segment_le_sdu(chan, &seg_queue, msg, len);
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci		if (chan->state != BT_CONNECTED) {
26988c2ecf20Sopenharmony_ci			__skb_queue_purge(&seg_queue);
26998c2ecf20Sopenharmony_ci			err = -ENOTCONN;
27008c2ecf20Sopenharmony_ci		}
27018c2ecf20Sopenharmony_ci
27028c2ecf20Sopenharmony_ci		if (err)
27038c2ecf20Sopenharmony_ci			return err;
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci		skb_queue_splice_tail_init(&seg_queue, &chan->tx_q);
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci		l2cap_le_flowctl_send(chan);
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci		if (!chan->tx_credits)
27108c2ecf20Sopenharmony_ci			chan->ops->suspend(chan);
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci		err = len;
27138c2ecf20Sopenharmony_ci
27148c2ecf20Sopenharmony_ci		break;
27158c2ecf20Sopenharmony_ci
27168c2ecf20Sopenharmony_ci	case L2CAP_MODE_BASIC:
27178c2ecf20Sopenharmony_ci		/* Check outgoing MTU */
27188c2ecf20Sopenharmony_ci		if (len > chan->omtu)
27198c2ecf20Sopenharmony_ci			return -EMSGSIZE;
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci		/* Create a basic PDU */
27228c2ecf20Sopenharmony_ci		skb = l2cap_create_basic_pdu(chan, msg, len);
27238c2ecf20Sopenharmony_ci		if (IS_ERR(skb))
27248c2ecf20Sopenharmony_ci			return PTR_ERR(skb);
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci		l2cap_do_send(chan, skb);
27278c2ecf20Sopenharmony_ci		err = len;
27288c2ecf20Sopenharmony_ci		break;
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
27318c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
27328c2ecf20Sopenharmony_ci		/* Check outgoing MTU */
27338c2ecf20Sopenharmony_ci		if (len > chan->omtu) {
27348c2ecf20Sopenharmony_ci			err = -EMSGSIZE;
27358c2ecf20Sopenharmony_ci			break;
27368c2ecf20Sopenharmony_ci		}
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci		__skb_queue_head_init(&seg_queue);
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci		/* Do segmentation before calling in to the state machine,
27418c2ecf20Sopenharmony_ci		 * since it's possible to block while waiting for memory
27428c2ecf20Sopenharmony_ci		 * allocation.
27438c2ecf20Sopenharmony_ci		 */
27448c2ecf20Sopenharmony_ci		err = l2cap_segment_sdu(chan, &seg_queue, msg, len);
27458c2ecf20Sopenharmony_ci
27468c2ecf20Sopenharmony_ci		if (err)
27478c2ecf20Sopenharmony_ci			break;
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci		if (chan->mode == L2CAP_MODE_ERTM)
27508c2ecf20Sopenharmony_ci			l2cap_tx(chan, NULL, &seg_queue, L2CAP_EV_DATA_REQUEST);
27518c2ecf20Sopenharmony_ci		else
27528c2ecf20Sopenharmony_ci			l2cap_streaming_send(chan, &seg_queue);
27538c2ecf20Sopenharmony_ci
27548c2ecf20Sopenharmony_ci		err = len;
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_ci		/* If the skbs were not queued for sending, they'll still be in
27578c2ecf20Sopenharmony_ci		 * seg_queue and need to be purged.
27588c2ecf20Sopenharmony_ci		 */
27598c2ecf20Sopenharmony_ci		__skb_queue_purge(&seg_queue);
27608c2ecf20Sopenharmony_ci		break;
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci	default:
27638c2ecf20Sopenharmony_ci		BT_DBG("bad state %1.1x", chan->mode);
27648c2ecf20Sopenharmony_ci		err = -EBADFD;
27658c2ecf20Sopenharmony_ci	}
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	return err;
27688c2ecf20Sopenharmony_ci}
27698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2cap_chan_send);
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_cistatic void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq)
27728c2ecf20Sopenharmony_ci{
27738c2ecf20Sopenharmony_ci	struct l2cap_ctrl control;
27748c2ecf20Sopenharmony_ci	u16 seq;
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	BT_DBG("chan %p, txseq %u", chan, txseq);
27778c2ecf20Sopenharmony_ci
27788c2ecf20Sopenharmony_ci	memset(&control, 0, sizeof(control));
27798c2ecf20Sopenharmony_ci	control.sframe = 1;
27808c2ecf20Sopenharmony_ci	control.super = L2CAP_SUPER_SREJ;
27818c2ecf20Sopenharmony_ci
27828c2ecf20Sopenharmony_ci	for (seq = chan->expected_tx_seq; seq != txseq;
27838c2ecf20Sopenharmony_ci	     seq = __next_seq(chan, seq)) {
27848c2ecf20Sopenharmony_ci		if (!l2cap_ertm_seq_in_queue(&chan->srej_q, seq)) {
27858c2ecf20Sopenharmony_ci			control.reqseq = seq;
27868c2ecf20Sopenharmony_ci			l2cap_send_sframe(chan, &control);
27878c2ecf20Sopenharmony_ci			l2cap_seq_list_append(&chan->srej_list, seq);
27888c2ecf20Sopenharmony_ci		}
27898c2ecf20Sopenharmony_ci	}
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	chan->expected_tx_seq = __next_seq(chan, txseq);
27928c2ecf20Sopenharmony_ci}
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_cistatic void l2cap_send_srej_tail(struct l2cap_chan *chan)
27958c2ecf20Sopenharmony_ci{
27968c2ecf20Sopenharmony_ci	struct l2cap_ctrl control;
27978c2ecf20Sopenharmony_ci
27988c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_ci	if (chan->srej_list.tail == L2CAP_SEQ_LIST_CLEAR)
28018c2ecf20Sopenharmony_ci		return;
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci	memset(&control, 0, sizeof(control));
28048c2ecf20Sopenharmony_ci	control.sframe = 1;
28058c2ecf20Sopenharmony_ci	control.super = L2CAP_SUPER_SREJ;
28068c2ecf20Sopenharmony_ci	control.reqseq = chan->srej_list.tail;
28078c2ecf20Sopenharmony_ci	l2cap_send_sframe(chan, &control);
28088c2ecf20Sopenharmony_ci}
28098c2ecf20Sopenharmony_ci
28108c2ecf20Sopenharmony_cistatic void l2cap_send_srej_list(struct l2cap_chan *chan, u16 txseq)
28118c2ecf20Sopenharmony_ci{
28128c2ecf20Sopenharmony_ci	struct l2cap_ctrl control;
28138c2ecf20Sopenharmony_ci	u16 initial_head;
28148c2ecf20Sopenharmony_ci	u16 seq;
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_ci	BT_DBG("chan %p, txseq %u", chan, txseq);
28178c2ecf20Sopenharmony_ci
28188c2ecf20Sopenharmony_ci	memset(&control, 0, sizeof(control));
28198c2ecf20Sopenharmony_ci	control.sframe = 1;
28208c2ecf20Sopenharmony_ci	control.super = L2CAP_SUPER_SREJ;
28218c2ecf20Sopenharmony_ci
28228c2ecf20Sopenharmony_ci	/* Capture initial list head to allow only one pass through the list. */
28238c2ecf20Sopenharmony_ci	initial_head = chan->srej_list.head;
28248c2ecf20Sopenharmony_ci
28258c2ecf20Sopenharmony_ci	do {
28268c2ecf20Sopenharmony_ci		seq = l2cap_seq_list_pop(&chan->srej_list);
28278c2ecf20Sopenharmony_ci		if (seq == txseq || seq == L2CAP_SEQ_LIST_CLEAR)
28288c2ecf20Sopenharmony_ci			break;
28298c2ecf20Sopenharmony_ci
28308c2ecf20Sopenharmony_ci		control.reqseq = seq;
28318c2ecf20Sopenharmony_ci		l2cap_send_sframe(chan, &control);
28328c2ecf20Sopenharmony_ci		l2cap_seq_list_append(&chan->srej_list, seq);
28338c2ecf20Sopenharmony_ci	} while (chan->srej_list.head != initial_head);
28348c2ecf20Sopenharmony_ci}
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_cistatic void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq)
28378c2ecf20Sopenharmony_ci{
28388c2ecf20Sopenharmony_ci	struct sk_buff *acked_skb;
28398c2ecf20Sopenharmony_ci	u16 ackseq;
28408c2ecf20Sopenharmony_ci
28418c2ecf20Sopenharmony_ci	BT_DBG("chan %p, reqseq %u", chan, reqseq);
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_ci	if (chan->unacked_frames == 0 || reqseq == chan->expected_ack_seq)
28448c2ecf20Sopenharmony_ci		return;
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci	BT_DBG("expected_ack_seq %u, unacked_frames %u",
28478c2ecf20Sopenharmony_ci	       chan->expected_ack_seq, chan->unacked_frames);
28488c2ecf20Sopenharmony_ci
28498c2ecf20Sopenharmony_ci	for (ackseq = chan->expected_ack_seq; ackseq != reqseq;
28508c2ecf20Sopenharmony_ci	     ackseq = __next_seq(chan, ackseq)) {
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci		acked_skb = l2cap_ertm_seq_in_queue(&chan->tx_q, ackseq);
28538c2ecf20Sopenharmony_ci		if (acked_skb) {
28548c2ecf20Sopenharmony_ci			skb_unlink(acked_skb, &chan->tx_q);
28558c2ecf20Sopenharmony_ci			kfree_skb(acked_skb);
28568c2ecf20Sopenharmony_ci			chan->unacked_frames--;
28578c2ecf20Sopenharmony_ci		}
28588c2ecf20Sopenharmony_ci	}
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_ci	chan->expected_ack_seq = reqseq;
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci	if (chan->unacked_frames == 0)
28638c2ecf20Sopenharmony_ci		__clear_retrans_timer(chan);
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci	BT_DBG("unacked_frames %u", chan->unacked_frames);
28668c2ecf20Sopenharmony_ci}
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_cistatic void l2cap_abort_rx_srej_sent(struct l2cap_chan *chan)
28698c2ecf20Sopenharmony_ci{
28708c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci	chan->expected_tx_seq = chan->buffer_seq;
28738c2ecf20Sopenharmony_ci	l2cap_seq_list_clear(&chan->srej_list);
28748c2ecf20Sopenharmony_ci	skb_queue_purge(&chan->srej_q);
28758c2ecf20Sopenharmony_ci	chan->rx_state = L2CAP_RX_STATE_RECV;
28768c2ecf20Sopenharmony_ci}
28778c2ecf20Sopenharmony_ci
28788c2ecf20Sopenharmony_cistatic void l2cap_tx_state_xmit(struct l2cap_chan *chan,
28798c2ecf20Sopenharmony_ci				struct l2cap_ctrl *control,
28808c2ecf20Sopenharmony_ci				struct sk_buff_head *skbs, u8 event)
28818c2ecf20Sopenharmony_ci{
28828c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p, skbs %p, event %d", chan, control, skbs,
28838c2ecf20Sopenharmony_ci	       event);
28848c2ecf20Sopenharmony_ci
28858c2ecf20Sopenharmony_ci	switch (event) {
28868c2ecf20Sopenharmony_ci	case L2CAP_EV_DATA_REQUEST:
28878c2ecf20Sopenharmony_ci		if (chan->tx_send_head == NULL)
28888c2ecf20Sopenharmony_ci			chan->tx_send_head = skb_peek(skbs);
28898c2ecf20Sopenharmony_ci
28908c2ecf20Sopenharmony_ci		skb_queue_splice_tail_init(skbs, &chan->tx_q);
28918c2ecf20Sopenharmony_ci		l2cap_ertm_send(chan);
28928c2ecf20Sopenharmony_ci		break;
28938c2ecf20Sopenharmony_ci	case L2CAP_EV_LOCAL_BUSY_DETECTED:
28948c2ecf20Sopenharmony_ci		BT_DBG("Enter LOCAL_BUSY");
28958c2ecf20Sopenharmony_ci		set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_ci		if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
28988c2ecf20Sopenharmony_ci			/* The SREJ_SENT state must be aborted if we are to
28998c2ecf20Sopenharmony_ci			 * enter the LOCAL_BUSY state.
29008c2ecf20Sopenharmony_ci			 */
29018c2ecf20Sopenharmony_ci			l2cap_abort_rx_srej_sent(chan);
29028c2ecf20Sopenharmony_ci		}
29038c2ecf20Sopenharmony_ci
29048c2ecf20Sopenharmony_ci		l2cap_send_ack(chan);
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci		break;
29078c2ecf20Sopenharmony_ci	case L2CAP_EV_LOCAL_BUSY_CLEAR:
29088c2ecf20Sopenharmony_ci		BT_DBG("Exit LOCAL_BUSY");
29098c2ecf20Sopenharmony_ci		clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
29108c2ecf20Sopenharmony_ci
29118c2ecf20Sopenharmony_ci		if (test_bit(CONN_RNR_SENT, &chan->conn_state)) {
29128c2ecf20Sopenharmony_ci			struct l2cap_ctrl local_control;
29138c2ecf20Sopenharmony_ci
29148c2ecf20Sopenharmony_ci			memset(&local_control, 0, sizeof(local_control));
29158c2ecf20Sopenharmony_ci			local_control.sframe = 1;
29168c2ecf20Sopenharmony_ci			local_control.super = L2CAP_SUPER_RR;
29178c2ecf20Sopenharmony_ci			local_control.poll = 1;
29188c2ecf20Sopenharmony_ci			local_control.reqseq = chan->buffer_seq;
29198c2ecf20Sopenharmony_ci			l2cap_send_sframe(chan, &local_control);
29208c2ecf20Sopenharmony_ci
29218c2ecf20Sopenharmony_ci			chan->retry_count = 1;
29228c2ecf20Sopenharmony_ci			__set_monitor_timer(chan);
29238c2ecf20Sopenharmony_ci			chan->tx_state = L2CAP_TX_STATE_WAIT_F;
29248c2ecf20Sopenharmony_ci		}
29258c2ecf20Sopenharmony_ci		break;
29268c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_REQSEQ_AND_FBIT:
29278c2ecf20Sopenharmony_ci		l2cap_process_reqseq(chan, control->reqseq);
29288c2ecf20Sopenharmony_ci		break;
29298c2ecf20Sopenharmony_ci	case L2CAP_EV_EXPLICIT_POLL:
29308c2ecf20Sopenharmony_ci		l2cap_send_rr_or_rnr(chan, 1);
29318c2ecf20Sopenharmony_ci		chan->retry_count = 1;
29328c2ecf20Sopenharmony_ci		__set_monitor_timer(chan);
29338c2ecf20Sopenharmony_ci		__clear_ack_timer(chan);
29348c2ecf20Sopenharmony_ci		chan->tx_state = L2CAP_TX_STATE_WAIT_F;
29358c2ecf20Sopenharmony_ci		break;
29368c2ecf20Sopenharmony_ci	case L2CAP_EV_RETRANS_TO:
29378c2ecf20Sopenharmony_ci		l2cap_send_rr_or_rnr(chan, 1);
29388c2ecf20Sopenharmony_ci		chan->retry_count = 1;
29398c2ecf20Sopenharmony_ci		__set_monitor_timer(chan);
29408c2ecf20Sopenharmony_ci		chan->tx_state = L2CAP_TX_STATE_WAIT_F;
29418c2ecf20Sopenharmony_ci		break;
29428c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_FBIT:
29438c2ecf20Sopenharmony_ci		/* Nothing to process */
29448c2ecf20Sopenharmony_ci		break;
29458c2ecf20Sopenharmony_ci	default:
29468c2ecf20Sopenharmony_ci		break;
29478c2ecf20Sopenharmony_ci	}
29488c2ecf20Sopenharmony_ci}
29498c2ecf20Sopenharmony_ci
29508c2ecf20Sopenharmony_cistatic void l2cap_tx_state_wait_f(struct l2cap_chan *chan,
29518c2ecf20Sopenharmony_ci				  struct l2cap_ctrl *control,
29528c2ecf20Sopenharmony_ci				  struct sk_buff_head *skbs, u8 event)
29538c2ecf20Sopenharmony_ci{
29548c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p, skbs %p, event %d", chan, control, skbs,
29558c2ecf20Sopenharmony_ci	       event);
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_ci	switch (event) {
29588c2ecf20Sopenharmony_ci	case L2CAP_EV_DATA_REQUEST:
29598c2ecf20Sopenharmony_ci		if (chan->tx_send_head == NULL)
29608c2ecf20Sopenharmony_ci			chan->tx_send_head = skb_peek(skbs);
29618c2ecf20Sopenharmony_ci		/* Queue data, but don't send. */
29628c2ecf20Sopenharmony_ci		skb_queue_splice_tail_init(skbs, &chan->tx_q);
29638c2ecf20Sopenharmony_ci		break;
29648c2ecf20Sopenharmony_ci	case L2CAP_EV_LOCAL_BUSY_DETECTED:
29658c2ecf20Sopenharmony_ci		BT_DBG("Enter LOCAL_BUSY");
29668c2ecf20Sopenharmony_ci		set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_ci		if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
29698c2ecf20Sopenharmony_ci			/* The SREJ_SENT state must be aborted if we are to
29708c2ecf20Sopenharmony_ci			 * enter the LOCAL_BUSY state.
29718c2ecf20Sopenharmony_ci			 */
29728c2ecf20Sopenharmony_ci			l2cap_abort_rx_srej_sent(chan);
29738c2ecf20Sopenharmony_ci		}
29748c2ecf20Sopenharmony_ci
29758c2ecf20Sopenharmony_ci		l2cap_send_ack(chan);
29768c2ecf20Sopenharmony_ci
29778c2ecf20Sopenharmony_ci		break;
29788c2ecf20Sopenharmony_ci	case L2CAP_EV_LOCAL_BUSY_CLEAR:
29798c2ecf20Sopenharmony_ci		BT_DBG("Exit LOCAL_BUSY");
29808c2ecf20Sopenharmony_ci		clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
29818c2ecf20Sopenharmony_ci
29828c2ecf20Sopenharmony_ci		if (test_bit(CONN_RNR_SENT, &chan->conn_state)) {
29838c2ecf20Sopenharmony_ci			struct l2cap_ctrl local_control;
29848c2ecf20Sopenharmony_ci			memset(&local_control, 0, sizeof(local_control));
29858c2ecf20Sopenharmony_ci			local_control.sframe = 1;
29868c2ecf20Sopenharmony_ci			local_control.super = L2CAP_SUPER_RR;
29878c2ecf20Sopenharmony_ci			local_control.poll = 1;
29888c2ecf20Sopenharmony_ci			local_control.reqseq = chan->buffer_seq;
29898c2ecf20Sopenharmony_ci			l2cap_send_sframe(chan, &local_control);
29908c2ecf20Sopenharmony_ci
29918c2ecf20Sopenharmony_ci			chan->retry_count = 1;
29928c2ecf20Sopenharmony_ci			__set_monitor_timer(chan);
29938c2ecf20Sopenharmony_ci			chan->tx_state = L2CAP_TX_STATE_WAIT_F;
29948c2ecf20Sopenharmony_ci		}
29958c2ecf20Sopenharmony_ci		break;
29968c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_REQSEQ_AND_FBIT:
29978c2ecf20Sopenharmony_ci		l2cap_process_reqseq(chan, control->reqseq);
29988c2ecf20Sopenharmony_ci		fallthrough;
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_FBIT:
30018c2ecf20Sopenharmony_ci		if (control && control->final) {
30028c2ecf20Sopenharmony_ci			__clear_monitor_timer(chan);
30038c2ecf20Sopenharmony_ci			if (chan->unacked_frames > 0)
30048c2ecf20Sopenharmony_ci				__set_retrans_timer(chan);
30058c2ecf20Sopenharmony_ci			chan->retry_count = 0;
30068c2ecf20Sopenharmony_ci			chan->tx_state = L2CAP_TX_STATE_XMIT;
30078c2ecf20Sopenharmony_ci			BT_DBG("recv fbit tx_state 0x2.2%x", chan->tx_state);
30088c2ecf20Sopenharmony_ci		}
30098c2ecf20Sopenharmony_ci		break;
30108c2ecf20Sopenharmony_ci	case L2CAP_EV_EXPLICIT_POLL:
30118c2ecf20Sopenharmony_ci		/* Ignore */
30128c2ecf20Sopenharmony_ci		break;
30138c2ecf20Sopenharmony_ci	case L2CAP_EV_MONITOR_TO:
30148c2ecf20Sopenharmony_ci		if (chan->max_tx == 0 || chan->retry_count < chan->max_tx) {
30158c2ecf20Sopenharmony_ci			l2cap_send_rr_or_rnr(chan, 1);
30168c2ecf20Sopenharmony_ci			__set_monitor_timer(chan);
30178c2ecf20Sopenharmony_ci			chan->retry_count++;
30188c2ecf20Sopenharmony_ci		} else {
30198c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, ECONNABORTED);
30208c2ecf20Sopenharmony_ci		}
30218c2ecf20Sopenharmony_ci		break;
30228c2ecf20Sopenharmony_ci	default:
30238c2ecf20Sopenharmony_ci		break;
30248c2ecf20Sopenharmony_ci	}
30258c2ecf20Sopenharmony_ci}
30268c2ecf20Sopenharmony_ci
30278c2ecf20Sopenharmony_cistatic void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
30288c2ecf20Sopenharmony_ci		     struct sk_buff_head *skbs, u8 event)
30298c2ecf20Sopenharmony_ci{
30308c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p, skbs %p, event %d, state %d",
30318c2ecf20Sopenharmony_ci	       chan, control, skbs, event, chan->tx_state);
30328c2ecf20Sopenharmony_ci
30338c2ecf20Sopenharmony_ci	switch (chan->tx_state) {
30348c2ecf20Sopenharmony_ci	case L2CAP_TX_STATE_XMIT:
30358c2ecf20Sopenharmony_ci		l2cap_tx_state_xmit(chan, control, skbs, event);
30368c2ecf20Sopenharmony_ci		break;
30378c2ecf20Sopenharmony_ci	case L2CAP_TX_STATE_WAIT_F:
30388c2ecf20Sopenharmony_ci		l2cap_tx_state_wait_f(chan, control, skbs, event);
30398c2ecf20Sopenharmony_ci		break;
30408c2ecf20Sopenharmony_ci	default:
30418c2ecf20Sopenharmony_ci		/* Ignore event */
30428c2ecf20Sopenharmony_ci		break;
30438c2ecf20Sopenharmony_ci	}
30448c2ecf20Sopenharmony_ci}
30458c2ecf20Sopenharmony_ci
30468c2ecf20Sopenharmony_cistatic void l2cap_pass_to_tx(struct l2cap_chan *chan,
30478c2ecf20Sopenharmony_ci			     struct l2cap_ctrl *control)
30488c2ecf20Sopenharmony_ci{
30498c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p", chan, control);
30508c2ecf20Sopenharmony_ci	l2cap_tx(chan, control, NULL, L2CAP_EV_RECV_REQSEQ_AND_FBIT);
30518c2ecf20Sopenharmony_ci}
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_cistatic void l2cap_pass_to_tx_fbit(struct l2cap_chan *chan,
30548c2ecf20Sopenharmony_ci				  struct l2cap_ctrl *control)
30558c2ecf20Sopenharmony_ci{
30568c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p", chan, control);
30578c2ecf20Sopenharmony_ci	l2cap_tx(chan, control, NULL, L2CAP_EV_RECV_FBIT);
30588c2ecf20Sopenharmony_ci}
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_ci/* Copy frame to all raw sockets on that connection */
30618c2ecf20Sopenharmony_cistatic void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
30628c2ecf20Sopenharmony_ci{
30638c2ecf20Sopenharmony_ci	struct sk_buff *nskb;
30648c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
30658c2ecf20Sopenharmony_ci
30668c2ecf20Sopenharmony_ci	BT_DBG("conn %p", conn);
30678c2ecf20Sopenharmony_ci
30688c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci	list_for_each_entry(chan, &conn->chan_l, list) {
30718c2ecf20Sopenharmony_ci		if (chan->chan_type != L2CAP_CHAN_RAW)
30728c2ecf20Sopenharmony_ci			continue;
30738c2ecf20Sopenharmony_ci
30748c2ecf20Sopenharmony_ci		/* Don't send frame to the channel it came from */
30758c2ecf20Sopenharmony_ci		if (bt_cb(skb)->l2cap.chan == chan)
30768c2ecf20Sopenharmony_ci			continue;
30778c2ecf20Sopenharmony_ci
30788c2ecf20Sopenharmony_ci		nskb = skb_clone(skb, GFP_KERNEL);
30798c2ecf20Sopenharmony_ci		if (!nskb)
30808c2ecf20Sopenharmony_ci			continue;
30818c2ecf20Sopenharmony_ci		if (chan->ops->recv(chan, nskb))
30828c2ecf20Sopenharmony_ci			kfree_skb(nskb);
30838c2ecf20Sopenharmony_ci	}
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
30868c2ecf20Sopenharmony_ci}
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_ci/* ---- L2CAP signalling commands ---- */
30898c2ecf20Sopenharmony_cistatic struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code,
30908c2ecf20Sopenharmony_ci				       u8 ident, u16 dlen, void *data)
30918c2ecf20Sopenharmony_ci{
30928c2ecf20Sopenharmony_ci	struct sk_buff *skb, **frag;
30938c2ecf20Sopenharmony_ci	struct l2cap_cmd_hdr *cmd;
30948c2ecf20Sopenharmony_ci	struct l2cap_hdr *lh;
30958c2ecf20Sopenharmony_ci	int len, count;
30968c2ecf20Sopenharmony_ci
30978c2ecf20Sopenharmony_ci	BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %u",
30988c2ecf20Sopenharmony_ci	       conn, code, ident, dlen);
30998c2ecf20Sopenharmony_ci
31008c2ecf20Sopenharmony_ci	if (conn->mtu < L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE)
31018c2ecf20Sopenharmony_ci		return NULL;
31028c2ecf20Sopenharmony_ci
31038c2ecf20Sopenharmony_ci	len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
31048c2ecf20Sopenharmony_ci	count = min_t(unsigned int, conn->mtu, len);
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_ci	skb = bt_skb_alloc(count, GFP_KERNEL);
31078c2ecf20Sopenharmony_ci	if (!skb)
31088c2ecf20Sopenharmony_ci		return NULL;
31098c2ecf20Sopenharmony_ci
31108c2ecf20Sopenharmony_ci	lh = skb_put(skb, L2CAP_HDR_SIZE);
31118c2ecf20Sopenharmony_ci	lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
31128c2ecf20Sopenharmony_ci
31138c2ecf20Sopenharmony_ci	if (conn->hcon->type == LE_LINK)
31148c2ecf20Sopenharmony_ci		lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
31158c2ecf20Sopenharmony_ci	else
31168c2ecf20Sopenharmony_ci		lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
31178c2ecf20Sopenharmony_ci
31188c2ecf20Sopenharmony_ci	cmd = skb_put(skb, L2CAP_CMD_HDR_SIZE);
31198c2ecf20Sopenharmony_ci	cmd->code  = code;
31208c2ecf20Sopenharmony_ci	cmd->ident = ident;
31218c2ecf20Sopenharmony_ci	cmd->len   = cpu_to_le16(dlen);
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_ci	if (dlen) {
31248c2ecf20Sopenharmony_ci		count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
31258c2ecf20Sopenharmony_ci		skb_put_data(skb, data, count);
31268c2ecf20Sopenharmony_ci		data += count;
31278c2ecf20Sopenharmony_ci	}
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci	len -= skb->len;
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci	/* Continuation fragments (no L2CAP header) */
31328c2ecf20Sopenharmony_ci	frag = &skb_shinfo(skb)->frag_list;
31338c2ecf20Sopenharmony_ci	while (len) {
31348c2ecf20Sopenharmony_ci		count = min_t(unsigned int, conn->mtu, len);
31358c2ecf20Sopenharmony_ci
31368c2ecf20Sopenharmony_ci		*frag = bt_skb_alloc(count, GFP_KERNEL);
31378c2ecf20Sopenharmony_ci		if (!*frag)
31388c2ecf20Sopenharmony_ci			goto fail;
31398c2ecf20Sopenharmony_ci
31408c2ecf20Sopenharmony_ci		skb_put_data(*frag, data, count);
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci		len  -= count;
31438c2ecf20Sopenharmony_ci		data += count;
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_ci		frag = &(*frag)->next;
31468c2ecf20Sopenharmony_ci	}
31478c2ecf20Sopenharmony_ci
31488c2ecf20Sopenharmony_ci	return skb;
31498c2ecf20Sopenharmony_ci
31508c2ecf20Sopenharmony_cifail:
31518c2ecf20Sopenharmony_ci	kfree_skb(skb);
31528c2ecf20Sopenharmony_ci	return NULL;
31538c2ecf20Sopenharmony_ci}
31548c2ecf20Sopenharmony_ci
31558c2ecf20Sopenharmony_cistatic inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen,
31568c2ecf20Sopenharmony_ci				     unsigned long *val)
31578c2ecf20Sopenharmony_ci{
31588c2ecf20Sopenharmony_ci	struct l2cap_conf_opt *opt = *ptr;
31598c2ecf20Sopenharmony_ci	int len;
31608c2ecf20Sopenharmony_ci
31618c2ecf20Sopenharmony_ci	len = L2CAP_CONF_OPT_SIZE + opt->len;
31628c2ecf20Sopenharmony_ci	*ptr += len;
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci	*type = opt->type;
31658c2ecf20Sopenharmony_ci	*olen = opt->len;
31668c2ecf20Sopenharmony_ci
31678c2ecf20Sopenharmony_ci	switch (opt->len) {
31688c2ecf20Sopenharmony_ci	case 1:
31698c2ecf20Sopenharmony_ci		*val = *((u8 *) opt->val);
31708c2ecf20Sopenharmony_ci		break;
31718c2ecf20Sopenharmony_ci
31728c2ecf20Sopenharmony_ci	case 2:
31738c2ecf20Sopenharmony_ci		*val = get_unaligned_le16(opt->val);
31748c2ecf20Sopenharmony_ci		break;
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	case 4:
31778c2ecf20Sopenharmony_ci		*val = get_unaligned_le32(opt->val);
31788c2ecf20Sopenharmony_ci		break;
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	default:
31818c2ecf20Sopenharmony_ci		*val = (unsigned long) opt->val;
31828c2ecf20Sopenharmony_ci		break;
31838c2ecf20Sopenharmony_ci	}
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci	BT_DBG("type 0x%2.2x len %u val 0x%lx", *type, opt->len, *val);
31868c2ecf20Sopenharmony_ci	return len;
31878c2ecf20Sopenharmony_ci}
31888c2ecf20Sopenharmony_ci
31898c2ecf20Sopenharmony_cistatic void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val, size_t size)
31908c2ecf20Sopenharmony_ci{
31918c2ecf20Sopenharmony_ci	struct l2cap_conf_opt *opt = *ptr;
31928c2ecf20Sopenharmony_ci
31938c2ecf20Sopenharmony_ci	BT_DBG("type 0x%2.2x len %u val 0x%lx", type, len, val);
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_ci	if (size < L2CAP_CONF_OPT_SIZE + len)
31968c2ecf20Sopenharmony_ci		return;
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci	opt->type = type;
31998c2ecf20Sopenharmony_ci	opt->len  = len;
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_ci	switch (len) {
32028c2ecf20Sopenharmony_ci	case 1:
32038c2ecf20Sopenharmony_ci		*((u8 *) opt->val)  = val;
32048c2ecf20Sopenharmony_ci		break;
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ci	case 2:
32078c2ecf20Sopenharmony_ci		put_unaligned_le16(val, opt->val);
32088c2ecf20Sopenharmony_ci		break;
32098c2ecf20Sopenharmony_ci
32108c2ecf20Sopenharmony_ci	case 4:
32118c2ecf20Sopenharmony_ci		put_unaligned_le32(val, opt->val);
32128c2ecf20Sopenharmony_ci		break;
32138c2ecf20Sopenharmony_ci
32148c2ecf20Sopenharmony_ci	default:
32158c2ecf20Sopenharmony_ci		memcpy(opt->val, (void *) val, len);
32168c2ecf20Sopenharmony_ci		break;
32178c2ecf20Sopenharmony_ci	}
32188c2ecf20Sopenharmony_ci
32198c2ecf20Sopenharmony_ci	*ptr += L2CAP_CONF_OPT_SIZE + len;
32208c2ecf20Sopenharmony_ci}
32218c2ecf20Sopenharmony_ci
32228c2ecf20Sopenharmony_cistatic void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan, size_t size)
32238c2ecf20Sopenharmony_ci{
32248c2ecf20Sopenharmony_ci	struct l2cap_conf_efs efs;
32258c2ecf20Sopenharmony_ci
32268c2ecf20Sopenharmony_ci	switch (chan->mode) {
32278c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
32288c2ecf20Sopenharmony_ci		efs.id		= chan->local_id;
32298c2ecf20Sopenharmony_ci		efs.stype	= chan->local_stype;
32308c2ecf20Sopenharmony_ci		efs.msdu	= cpu_to_le16(chan->local_msdu);
32318c2ecf20Sopenharmony_ci		efs.sdu_itime	= cpu_to_le32(chan->local_sdu_itime);
32328c2ecf20Sopenharmony_ci		efs.acc_lat	= cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
32338c2ecf20Sopenharmony_ci		efs.flush_to	= cpu_to_le32(L2CAP_EFS_DEFAULT_FLUSH_TO);
32348c2ecf20Sopenharmony_ci		break;
32358c2ecf20Sopenharmony_ci
32368c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
32378c2ecf20Sopenharmony_ci		efs.id		= 1;
32388c2ecf20Sopenharmony_ci		efs.stype	= L2CAP_SERV_BESTEFFORT;
32398c2ecf20Sopenharmony_ci		efs.msdu	= cpu_to_le16(chan->local_msdu);
32408c2ecf20Sopenharmony_ci		efs.sdu_itime	= cpu_to_le32(chan->local_sdu_itime);
32418c2ecf20Sopenharmony_ci		efs.acc_lat	= 0;
32428c2ecf20Sopenharmony_ci		efs.flush_to	= 0;
32438c2ecf20Sopenharmony_ci		break;
32448c2ecf20Sopenharmony_ci
32458c2ecf20Sopenharmony_ci	default:
32468c2ecf20Sopenharmony_ci		return;
32478c2ecf20Sopenharmony_ci	}
32488c2ecf20Sopenharmony_ci
32498c2ecf20Sopenharmony_ci	l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
32508c2ecf20Sopenharmony_ci			   (unsigned long) &efs, size);
32518c2ecf20Sopenharmony_ci}
32528c2ecf20Sopenharmony_ci
32538c2ecf20Sopenharmony_cistatic void l2cap_ack_timeout(struct work_struct *work)
32548c2ecf20Sopenharmony_ci{
32558c2ecf20Sopenharmony_ci	struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
32568c2ecf20Sopenharmony_ci					       ack_timer.work);
32578c2ecf20Sopenharmony_ci	u16 frames_to_ack;
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
32608c2ecf20Sopenharmony_ci
32618c2ecf20Sopenharmony_ci	l2cap_chan_lock(chan);
32628c2ecf20Sopenharmony_ci
32638c2ecf20Sopenharmony_ci	frames_to_ack = __seq_offset(chan, chan->buffer_seq,
32648c2ecf20Sopenharmony_ci				     chan->last_acked_seq);
32658c2ecf20Sopenharmony_ci
32668c2ecf20Sopenharmony_ci	if (frames_to_ack)
32678c2ecf20Sopenharmony_ci		l2cap_send_rr_or_rnr(chan, 0);
32688c2ecf20Sopenharmony_ci
32698c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
32708c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
32718c2ecf20Sopenharmony_ci}
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ciint l2cap_ertm_init(struct l2cap_chan *chan)
32748c2ecf20Sopenharmony_ci{
32758c2ecf20Sopenharmony_ci	int err;
32768c2ecf20Sopenharmony_ci
32778c2ecf20Sopenharmony_ci	chan->next_tx_seq = 0;
32788c2ecf20Sopenharmony_ci	chan->expected_tx_seq = 0;
32798c2ecf20Sopenharmony_ci	chan->expected_ack_seq = 0;
32808c2ecf20Sopenharmony_ci	chan->unacked_frames = 0;
32818c2ecf20Sopenharmony_ci	chan->buffer_seq = 0;
32828c2ecf20Sopenharmony_ci	chan->frames_sent = 0;
32838c2ecf20Sopenharmony_ci	chan->last_acked_seq = 0;
32848c2ecf20Sopenharmony_ci	chan->sdu = NULL;
32858c2ecf20Sopenharmony_ci	chan->sdu_last_frag = NULL;
32868c2ecf20Sopenharmony_ci	chan->sdu_len = 0;
32878c2ecf20Sopenharmony_ci
32888c2ecf20Sopenharmony_ci	skb_queue_head_init(&chan->tx_q);
32898c2ecf20Sopenharmony_ci
32908c2ecf20Sopenharmony_ci	chan->local_amp_id = AMP_ID_BREDR;
32918c2ecf20Sopenharmony_ci	chan->move_id = AMP_ID_BREDR;
32928c2ecf20Sopenharmony_ci	chan->move_state = L2CAP_MOVE_STABLE;
32938c2ecf20Sopenharmony_ci	chan->move_role = L2CAP_MOVE_ROLE_NONE;
32948c2ecf20Sopenharmony_ci
32958c2ecf20Sopenharmony_ci	if (chan->mode != L2CAP_MODE_ERTM)
32968c2ecf20Sopenharmony_ci		return 0;
32978c2ecf20Sopenharmony_ci
32988c2ecf20Sopenharmony_ci	chan->rx_state = L2CAP_RX_STATE_RECV;
32998c2ecf20Sopenharmony_ci	chan->tx_state = L2CAP_TX_STATE_XMIT;
33008c2ecf20Sopenharmony_ci
33018c2ecf20Sopenharmony_ci	skb_queue_head_init(&chan->srej_q);
33028c2ecf20Sopenharmony_ci
33038c2ecf20Sopenharmony_ci	err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win);
33048c2ecf20Sopenharmony_ci	if (err < 0)
33058c2ecf20Sopenharmony_ci		return err;
33068c2ecf20Sopenharmony_ci
33078c2ecf20Sopenharmony_ci	err = l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win);
33088c2ecf20Sopenharmony_ci	if (err < 0)
33098c2ecf20Sopenharmony_ci		l2cap_seq_list_free(&chan->srej_list);
33108c2ecf20Sopenharmony_ci
33118c2ecf20Sopenharmony_ci	return err;
33128c2ecf20Sopenharmony_ci}
33138c2ecf20Sopenharmony_ci
33148c2ecf20Sopenharmony_cistatic inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
33158c2ecf20Sopenharmony_ci{
33168c2ecf20Sopenharmony_ci	switch (mode) {
33178c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
33188c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
33198c2ecf20Sopenharmony_ci		if (l2cap_mode_supported(mode, remote_feat_mask))
33208c2ecf20Sopenharmony_ci			return mode;
33218c2ecf20Sopenharmony_ci		fallthrough;
33228c2ecf20Sopenharmony_ci	default:
33238c2ecf20Sopenharmony_ci		return L2CAP_MODE_BASIC;
33248c2ecf20Sopenharmony_ci	}
33258c2ecf20Sopenharmony_ci}
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_cistatic inline bool __l2cap_ews_supported(struct l2cap_conn *conn)
33288c2ecf20Sopenharmony_ci{
33298c2ecf20Sopenharmony_ci	return ((conn->local_fixed_chan & L2CAP_FC_A2MP) &&
33308c2ecf20Sopenharmony_ci		(conn->feat_mask & L2CAP_FEAT_EXT_WINDOW));
33318c2ecf20Sopenharmony_ci}
33328c2ecf20Sopenharmony_ci
33338c2ecf20Sopenharmony_cistatic inline bool __l2cap_efs_supported(struct l2cap_conn *conn)
33348c2ecf20Sopenharmony_ci{
33358c2ecf20Sopenharmony_ci	return ((conn->local_fixed_chan & L2CAP_FC_A2MP) &&
33368c2ecf20Sopenharmony_ci		(conn->feat_mask & L2CAP_FEAT_EXT_FLOW));
33378c2ecf20Sopenharmony_ci}
33388c2ecf20Sopenharmony_ci
33398c2ecf20Sopenharmony_cistatic void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan,
33408c2ecf20Sopenharmony_ci				      struct l2cap_conf_rfc *rfc)
33418c2ecf20Sopenharmony_ci{
33428c2ecf20Sopenharmony_ci	if (chan->local_amp_id != AMP_ID_BREDR && chan->hs_hcon) {
33438c2ecf20Sopenharmony_ci		u64 ertm_to = chan->hs_hcon->hdev->amp_be_flush_to;
33448c2ecf20Sopenharmony_ci
33458c2ecf20Sopenharmony_ci		/* Class 1 devices have must have ERTM timeouts
33468c2ecf20Sopenharmony_ci		 * exceeding the Link Supervision Timeout.  The
33478c2ecf20Sopenharmony_ci		 * default Link Supervision Timeout for AMP
33488c2ecf20Sopenharmony_ci		 * controllers is 10 seconds.
33498c2ecf20Sopenharmony_ci		 *
33508c2ecf20Sopenharmony_ci		 * Class 1 devices use 0xffffffff for their
33518c2ecf20Sopenharmony_ci		 * best-effort flush timeout, so the clamping logic
33528c2ecf20Sopenharmony_ci		 * will result in a timeout that meets the above
33538c2ecf20Sopenharmony_ci		 * requirement.  ERTM timeouts are 16-bit values, so
33548c2ecf20Sopenharmony_ci		 * the maximum timeout is 65.535 seconds.
33558c2ecf20Sopenharmony_ci		 */
33568c2ecf20Sopenharmony_ci
33578c2ecf20Sopenharmony_ci		/* Convert timeout to milliseconds and round */
33588c2ecf20Sopenharmony_ci		ertm_to = DIV_ROUND_UP_ULL(ertm_to, 1000);
33598c2ecf20Sopenharmony_ci
33608c2ecf20Sopenharmony_ci		/* This is the recommended formula for class 2 devices
33618c2ecf20Sopenharmony_ci		 * that start ERTM timers when packets are sent to the
33628c2ecf20Sopenharmony_ci		 * controller.
33638c2ecf20Sopenharmony_ci		 */
33648c2ecf20Sopenharmony_ci		ertm_to = 3 * ertm_to + 500;
33658c2ecf20Sopenharmony_ci
33668c2ecf20Sopenharmony_ci		if (ertm_to > 0xffff)
33678c2ecf20Sopenharmony_ci			ertm_to = 0xffff;
33688c2ecf20Sopenharmony_ci
33698c2ecf20Sopenharmony_ci		rfc->retrans_timeout = cpu_to_le16((u16) ertm_to);
33708c2ecf20Sopenharmony_ci		rfc->monitor_timeout = rfc->retrans_timeout;
33718c2ecf20Sopenharmony_ci	} else {
33728c2ecf20Sopenharmony_ci		rfc->retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
33738c2ecf20Sopenharmony_ci		rfc->monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
33748c2ecf20Sopenharmony_ci	}
33758c2ecf20Sopenharmony_ci}
33768c2ecf20Sopenharmony_ci
33778c2ecf20Sopenharmony_cistatic inline void l2cap_txwin_setup(struct l2cap_chan *chan)
33788c2ecf20Sopenharmony_ci{
33798c2ecf20Sopenharmony_ci	if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
33808c2ecf20Sopenharmony_ci	    __l2cap_ews_supported(chan->conn)) {
33818c2ecf20Sopenharmony_ci		/* use extended control field */
33828c2ecf20Sopenharmony_ci		set_bit(FLAG_EXT_CTRL, &chan->flags);
33838c2ecf20Sopenharmony_ci		chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
33848c2ecf20Sopenharmony_ci	} else {
33858c2ecf20Sopenharmony_ci		chan->tx_win = min_t(u16, chan->tx_win,
33868c2ecf20Sopenharmony_ci				     L2CAP_DEFAULT_TX_WINDOW);
33878c2ecf20Sopenharmony_ci		chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
33888c2ecf20Sopenharmony_ci	}
33898c2ecf20Sopenharmony_ci	chan->ack_win = chan->tx_win;
33908c2ecf20Sopenharmony_ci}
33918c2ecf20Sopenharmony_ci
33928c2ecf20Sopenharmony_cistatic void l2cap_mtu_auto(struct l2cap_chan *chan)
33938c2ecf20Sopenharmony_ci{
33948c2ecf20Sopenharmony_ci	struct hci_conn *conn = chan->conn->hcon;
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_ci	chan->imtu = L2CAP_DEFAULT_MIN_MTU;
33978c2ecf20Sopenharmony_ci
33988c2ecf20Sopenharmony_ci	/* The 2-DH1 packet has between 2 and 56 information bytes
33998c2ecf20Sopenharmony_ci	 * (including the 2-byte payload header)
34008c2ecf20Sopenharmony_ci	 */
34018c2ecf20Sopenharmony_ci	if (!(conn->pkt_type & HCI_2DH1))
34028c2ecf20Sopenharmony_ci		chan->imtu = 54;
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci	/* The 3-DH1 packet has between 2 and 85 information bytes
34058c2ecf20Sopenharmony_ci	 * (including the 2-byte payload header)
34068c2ecf20Sopenharmony_ci	 */
34078c2ecf20Sopenharmony_ci	if (!(conn->pkt_type & HCI_3DH1))
34088c2ecf20Sopenharmony_ci		chan->imtu = 83;
34098c2ecf20Sopenharmony_ci
34108c2ecf20Sopenharmony_ci	/* The 2-DH3 packet has between 2 and 369 information bytes
34118c2ecf20Sopenharmony_ci	 * (including the 2-byte payload header)
34128c2ecf20Sopenharmony_ci	 */
34138c2ecf20Sopenharmony_ci	if (!(conn->pkt_type & HCI_2DH3))
34148c2ecf20Sopenharmony_ci		chan->imtu = 367;
34158c2ecf20Sopenharmony_ci
34168c2ecf20Sopenharmony_ci	/* The 3-DH3 packet has between 2 and 554 information bytes
34178c2ecf20Sopenharmony_ci	 * (including the 2-byte payload header)
34188c2ecf20Sopenharmony_ci	 */
34198c2ecf20Sopenharmony_ci	if (!(conn->pkt_type & HCI_3DH3))
34208c2ecf20Sopenharmony_ci		chan->imtu = 552;
34218c2ecf20Sopenharmony_ci
34228c2ecf20Sopenharmony_ci	/* The 2-DH5 packet has between 2 and 681 information bytes
34238c2ecf20Sopenharmony_ci	 * (including the 2-byte payload header)
34248c2ecf20Sopenharmony_ci	 */
34258c2ecf20Sopenharmony_ci	if (!(conn->pkt_type & HCI_2DH5))
34268c2ecf20Sopenharmony_ci		chan->imtu = 679;
34278c2ecf20Sopenharmony_ci
34288c2ecf20Sopenharmony_ci	/* The 3-DH5 packet has between 2 and 1023 information bytes
34298c2ecf20Sopenharmony_ci	 * (including the 2-byte payload header)
34308c2ecf20Sopenharmony_ci	 */
34318c2ecf20Sopenharmony_ci	if (!(conn->pkt_type & HCI_3DH5))
34328c2ecf20Sopenharmony_ci		chan->imtu = 1021;
34338c2ecf20Sopenharmony_ci}
34348c2ecf20Sopenharmony_ci
34358c2ecf20Sopenharmony_cistatic int l2cap_build_conf_req(struct l2cap_chan *chan, void *data, size_t data_size)
34368c2ecf20Sopenharmony_ci{
34378c2ecf20Sopenharmony_ci	struct l2cap_conf_req *req = data;
34388c2ecf20Sopenharmony_ci	struct l2cap_conf_rfc rfc = { .mode = chan->mode };
34398c2ecf20Sopenharmony_ci	void *ptr = req->data;
34408c2ecf20Sopenharmony_ci	void *endptr = data + data_size;
34418c2ecf20Sopenharmony_ci	u16 size;
34428c2ecf20Sopenharmony_ci
34438c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
34448c2ecf20Sopenharmony_ci
34458c2ecf20Sopenharmony_ci	if (chan->num_conf_req || chan->num_conf_rsp)
34468c2ecf20Sopenharmony_ci		goto done;
34478c2ecf20Sopenharmony_ci
34488c2ecf20Sopenharmony_ci	switch (chan->mode) {
34498c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
34508c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
34518c2ecf20Sopenharmony_ci		if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
34528c2ecf20Sopenharmony_ci			break;
34538c2ecf20Sopenharmony_ci
34548c2ecf20Sopenharmony_ci		if (__l2cap_efs_supported(chan->conn))
34558c2ecf20Sopenharmony_ci			set_bit(FLAG_EFS_ENABLE, &chan->flags);
34568c2ecf20Sopenharmony_ci
34578c2ecf20Sopenharmony_ci		fallthrough;
34588c2ecf20Sopenharmony_ci	default:
34598c2ecf20Sopenharmony_ci		chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
34608c2ecf20Sopenharmony_ci		break;
34618c2ecf20Sopenharmony_ci	}
34628c2ecf20Sopenharmony_ci
34638c2ecf20Sopenharmony_cidone:
34648c2ecf20Sopenharmony_ci	if (chan->imtu != L2CAP_DEFAULT_MTU) {
34658c2ecf20Sopenharmony_ci		if (!chan->imtu)
34668c2ecf20Sopenharmony_ci			l2cap_mtu_auto(chan);
34678c2ecf20Sopenharmony_ci		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu,
34688c2ecf20Sopenharmony_ci				   endptr - ptr);
34698c2ecf20Sopenharmony_ci	}
34708c2ecf20Sopenharmony_ci
34718c2ecf20Sopenharmony_ci	switch (chan->mode) {
34728c2ecf20Sopenharmony_ci	case L2CAP_MODE_BASIC:
34738c2ecf20Sopenharmony_ci		if (disable_ertm)
34748c2ecf20Sopenharmony_ci			break;
34758c2ecf20Sopenharmony_ci
34768c2ecf20Sopenharmony_ci		if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
34778c2ecf20Sopenharmony_ci		    !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
34788c2ecf20Sopenharmony_ci			break;
34798c2ecf20Sopenharmony_ci
34808c2ecf20Sopenharmony_ci		rfc.mode            = L2CAP_MODE_BASIC;
34818c2ecf20Sopenharmony_ci		rfc.txwin_size      = 0;
34828c2ecf20Sopenharmony_ci		rfc.max_transmit    = 0;
34838c2ecf20Sopenharmony_ci		rfc.retrans_timeout = 0;
34848c2ecf20Sopenharmony_ci		rfc.monitor_timeout = 0;
34858c2ecf20Sopenharmony_ci		rfc.max_pdu_size    = 0;
34868c2ecf20Sopenharmony_ci
34878c2ecf20Sopenharmony_ci		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
34888c2ecf20Sopenharmony_ci				   (unsigned long) &rfc, endptr - ptr);
34898c2ecf20Sopenharmony_ci		break;
34908c2ecf20Sopenharmony_ci
34918c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
34928c2ecf20Sopenharmony_ci		rfc.mode            = L2CAP_MODE_ERTM;
34938c2ecf20Sopenharmony_ci		rfc.max_transmit    = chan->max_tx;
34948c2ecf20Sopenharmony_ci
34958c2ecf20Sopenharmony_ci		__l2cap_set_ertm_timeouts(chan, &rfc);
34968c2ecf20Sopenharmony_ci
34978c2ecf20Sopenharmony_ci		size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
34988c2ecf20Sopenharmony_ci			     L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE -
34998c2ecf20Sopenharmony_ci			     L2CAP_FCS_SIZE);
35008c2ecf20Sopenharmony_ci		rfc.max_pdu_size = cpu_to_le16(size);
35018c2ecf20Sopenharmony_ci
35028c2ecf20Sopenharmony_ci		l2cap_txwin_setup(chan);
35038c2ecf20Sopenharmony_ci
35048c2ecf20Sopenharmony_ci		rfc.txwin_size = min_t(u16, chan->tx_win,
35058c2ecf20Sopenharmony_ci				       L2CAP_DEFAULT_TX_WINDOW);
35068c2ecf20Sopenharmony_ci
35078c2ecf20Sopenharmony_ci		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
35088c2ecf20Sopenharmony_ci				   (unsigned long) &rfc, endptr - ptr);
35098c2ecf20Sopenharmony_ci
35108c2ecf20Sopenharmony_ci		if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
35118c2ecf20Sopenharmony_ci			l2cap_add_opt_efs(&ptr, chan, endptr - ptr);
35128c2ecf20Sopenharmony_ci
35138c2ecf20Sopenharmony_ci		if (test_bit(FLAG_EXT_CTRL, &chan->flags))
35148c2ecf20Sopenharmony_ci			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
35158c2ecf20Sopenharmony_ci					   chan->tx_win, endptr - ptr);
35168c2ecf20Sopenharmony_ci
35178c2ecf20Sopenharmony_ci		if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
35188c2ecf20Sopenharmony_ci			if (chan->fcs == L2CAP_FCS_NONE ||
35198c2ecf20Sopenharmony_ci			    test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
35208c2ecf20Sopenharmony_ci				chan->fcs = L2CAP_FCS_NONE;
35218c2ecf20Sopenharmony_ci				l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
35228c2ecf20Sopenharmony_ci						   chan->fcs, endptr - ptr);
35238c2ecf20Sopenharmony_ci			}
35248c2ecf20Sopenharmony_ci		break;
35258c2ecf20Sopenharmony_ci
35268c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
35278c2ecf20Sopenharmony_ci		l2cap_txwin_setup(chan);
35288c2ecf20Sopenharmony_ci		rfc.mode            = L2CAP_MODE_STREAMING;
35298c2ecf20Sopenharmony_ci		rfc.txwin_size      = 0;
35308c2ecf20Sopenharmony_ci		rfc.max_transmit    = 0;
35318c2ecf20Sopenharmony_ci		rfc.retrans_timeout = 0;
35328c2ecf20Sopenharmony_ci		rfc.monitor_timeout = 0;
35338c2ecf20Sopenharmony_ci
35348c2ecf20Sopenharmony_ci		size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
35358c2ecf20Sopenharmony_ci			     L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE -
35368c2ecf20Sopenharmony_ci			     L2CAP_FCS_SIZE);
35378c2ecf20Sopenharmony_ci		rfc.max_pdu_size = cpu_to_le16(size);
35388c2ecf20Sopenharmony_ci
35398c2ecf20Sopenharmony_ci		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
35408c2ecf20Sopenharmony_ci				   (unsigned long) &rfc, endptr - ptr);
35418c2ecf20Sopenharmony_ci
35428c2ecf20Sopenharmony_ci		if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
35438c2ecf20Sopenharmony_ci			l2cap_add_opt_efs(&ptr, chan, endptr - ptr);
35448c2ecf20Sopenharmony_ci
35458c2ecf20Sopenharmony_ci		if (chan->conn->feat_mask & L2CAP_FEAT_FCS)
35468c2ecf20Sopenharmony_ci			if (chan->fcs == L2CAP_FCS_NONE ||
35478c2ecf20Sopenharmony_ci			    test_bit(CONF_RECV_NO_FCS, &chan->conf_state)) {
35488c2ecf20Sopenharmony_ci				chan->fcs = L2CAP_FCS_NONE;
35498c2ecf20Sopenharmony_ci				l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1,
35508c2ecf20Sopenharmony_ci						   chan->fcs, endptr - ptr);
35518c2ecf20Sopenharmony_ci			}
35528c2ecf20Sopenharmony_ci		break;
35538c2ecf20Sopenharmony_ci	}
35548c2ecf20Sopenharmony_ci
35558c2ecf20Sopenharmony_ci	req->dcid  = cpu_to_le16(chan->dcid);
35568c2ecf20Sopenharmony_ci	req->flags = cpu_to_le16(0);
35578c2ecf20Sopenharmony_ci
35588c2ecf20Sopenharmony_ci	return ptr - data;
35598c2ecf20Sopenharmony_ci}
35608c2ecf20Sopenharmony_ci
35618c2ecf20Sopenharmony_cistatic int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data, size_t data_size)
35628c2ecf20Sopenharmony_ci{
35638c2ecf20Sopenharmony_ci	struct l2cap_conf_rsp *rsp = data;
35648c2ecf20Sopenharmony_ci	void *ptr = rsp->data;
35658c2ecf20Sopenharmony_ci	void *endptr = data + data_size;
35668c2ecf20Sopenharmony_ci	void *req = chan->conf_req;
35678c2ecf20Sopenharmony_ci	int len = chan->conf_len;
35688c2ecf20Sopenharmony_ci	int type, hint, olen;
35698c2ecf20Sopenharmony_ci	unsigned long val;
35708c2ecf20Sopenharmony_ci	struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
35718c2ecf20Sopenharmony_ci	struct l2cap_conf_efs efs;
35728c2ecf20Sopenharmony_ci	u8 remote_efs = 0;
35738c2ecf20Sopenharmony_ci	u16 mtu = L2CAP_DEFAULT_MTU;
35748c2ecf20Sopenharmony_ci	u16 result = L2CAP_CONF_SUCCESS;
35758c2ecf20Sopenharmony_ci	u16 size;
35768c2ecf20Sopenharmony_ci
35778c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
35788c2ecf20Sopenharmony_ci
35798c2ecf20Sopenharmony_ci	while (len >= L2CAP_CONF_OPT_SIZE) {
35808c2ecf20Sopenharmony_ci		len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
35818c2ecf20Sopenharmony_ci		if (len < 0)
35828c2ecf20Sopenharmony_ci			break;
35838c2ecf20Sopenharmony_ci
35848c2ecf20Sopenharmony_ci		hint  = type & L2CAP_CONF_HINT;
35858c2ecf20Sopenharmony_ci		type &= L2CAP_CONF_MASK;
35868c2ecf20Sopenharmony_ci
35878c2ecf20Sopenharmony_ci		switch (type) {
35888c2ecf20Sopenharmony_ci		case L2CAP_CONF_MTU:
35898c2ecf20Sopenharmony_ci			if (olen != 2)
35908c2ecf20Sopenharmony_ci				break;
35918c2ecf20Sopenharmony_ci			mtu = val;
35928c2ecf20Sopenharmony_ci			break;
35938c2ecf20Sopenharmony_ci
35948c2ecf20Sopenharmony_ci		case L2CAP_CONF_FLUSH_TO:
35958c2ecf20Sopenharmony_ci			if (olen != 2)
35968c2ecf20Sopenharmony_ci				break;
35978c2ecf20Sopenharmony_ci			chan->flush_to = val;
35988c2ecf20Sopenharmony_ci			break;
35998c2ecf20Sopenharmony_ci
36008c2ecf20Sopenharmony_ci		case L2CAP_CONF_QOS:
36018c2ecf20Sopenharmony_ci			break;
36028c2ecf20Sopenharmony_ci
36038c2ecf20Sopenharmony_ci		case L2CAP_CONF_RFC:
36048c2ecf20Sopenharmony_ci			if (olen != sizeof(rfc))
36058c2ecf20Sopenharmony_ci				break;
36068c2ecf20Sopenharmony_ci			memcpy(&rfc, (void *) val, olen);
36078c2ecf20Sopenharmony_ci			break;
36088c2ecf20Sopenharmony_ci
36098c2ecf20Sopenharmony_ci		case L2CAP_CONF_FCS:
36108c2ecf20Sopenharmony_ci			if (olen != 1)
36118c2ecf20Sopenharmony_ci				break;
36128c2ecf20Sopenharmony_ci			if (val == L2CAP_FCS_NONE)
36138c2ecf20Sopenharmony_ci				set_bit(CONF_RECV_NO_FCS, &chan->conf_state);
36148c2ecf20Sopenharmony_ci			break;
36158c2ecf20Sopenharmony_ci
36168c2ecf20Sopenharmony_ci		case L2CAP_CONF_EFS:
36178c2ecf20Sopenharmony_ci			if (olen != sizeof(efs))
36188c2ecf20Sopenharmony_ci				break;
36198c2ecf20Sopenharmony_ci			remote_efs = 1;
36208c2ecf20Sopenharmony_ci			memcpy(&efs, (void *) val, olen);
36218c2ecf20Sopenharmony_ci			break;
36228c2ecf20Sopenharmony_ci
36238c2ecf20Sopenharmony_ci		case L2CAP_CONF_EWS:
36248c2ecf20Sopenharmony_ci			if (olen != 2)
36258c2ecf20Sopenharmony_ci				break;
36268c2ecf20Sopenharmony_ci			if (!(chan->conn->local_fixed_chan & L2CAP_FC_A2MP))
36278c2ecf20Sopenharmony_ci				return -ECONNREFUSED;
36288c2ecf20Sopenharmony_ci			set_bit(FLAG_EXT_CTRL, &chan->flags);
36298c2ecf20Sopenharmony_ci			set_bit(CONF_EWS_RECV, &chan->conf_state);
36308c2ecf20Sopenharmony_ci			chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
36318c2ecf20Sopenharmony_ci			chan->remote_tx_win = val;
36328c2ecf20Sopenharmony_ci			break;
36338c2ecf20Sopenharmony_ci
36348c2ecf20Sopenharmony_ci		default:
36358c2ecf20Sopenharmony_ci			if (hint)
36368c2ecf20Sopenharmony_ci				break;
36378c2ecf20Sopenharmony_ci			result = L2CAP_CONF_UNKNOWN;
36388c2ecf20Sopenharmony_ci			*((u8 *) ptr++) = type;
36398c2ecf20Sopenharmony_ci			break;
36408c2ecf20Sopenharmony_ci		}
36418c2ecf20Sopenharmony_ci	}
36428c2ecf20Sopenharmony_ci
36438c2ecf20Sopenharmony_ci	if (chan->num_conf_rsp || chan->num_conf_req > 1)
36448c2ecf20Sopenharmony_ci		goto done;
36458c2ecf20Sopenharmony_ci
36468c2ecf20Sopenharmony_ci	switch (chan->mode) {
36478c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
36488c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
36498c2ecf20Sopenharmony_ci		if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
36508c2ecf20Sopenharmony_ci			chan->mode = l2cap_select_mode(rfc.mode,
36518c2ecf20Sopenharmony_ci						       chan->conn->feat_mask);
36528c2ecf20Sopenharmony_ci			break;
36538c2ecf20Sopenharmony_ci		}
36548c2ecf20Sopenharmony_ci
36558c2ecf20Sopenharmony_ci		if (remote_efs) {
36568c2ecf20Sopenharmony_ci			if (__l2cap_efs_supported(chan->conn))
36578c2ecf20Sopenharmony_ci				set_bit(FLAG_EFS_ENABLE, &chan->flags);
36588c2ecf20Sopenharmony_ci			else
36598c2ecf20Sopenharmony_ci				return -ECONNREFUSED;
36608c2ecf20Sopenharmony_ci		}
36618c2ecf20Sopenharmony_ci
36628c2ecf20Sopenharmony_ci		if (chan->mode != rfc.mode)
36638c2ecf20Sopenharmony_ci			return -ECONNREFUSED;
36648c2ecf20Sopenharmony_ci
36658c2ecf20Sopenharmony_ci		break;
36668c2ecf20Sopenharmony_ci	}
36678c2ecf20Sopenharmony_ci
36688c2ecf20Sopenharmony_cidone:
36698c2ecf20Sopenharmony_ci	if (chan->mode != rfc.mode) {
36708c2ecf20Sopenharmony_ci		result = L2CAP_CONF_UNACCEPT;
36718c2ecf20Sopenharmony_ci		rfc.mode = chan->mode;
36728c2ecf20Sopenharmony_ci
36738c2ecf20Sopenharmony_ci		if (chan->num_conf_rsp == 1)
36748c2ecf20Sopenharmony_ci			return -ECONNREFUSED;
36758c2ecf20Sopenharmony_ci
36768c2ecf20Sopenharmony_ci		l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
36778c2ecf20Sopenharmony_ci				   (unsigned long) &rfc, endptr - ptr);
36788c2ecf20Sopenharmony_ci	}
36798c2ecf20Sopenharmony_ci
36808c2ecf20Sopenharmony_ci	if (result == L2CAP_CONF_SUCCESS) {
36818c2ecf20Sopenharmony_ci		/* Configure output options and let the other side know
36828c2ecf20Sopenharmony_ci		 * which ones we don't like. */
36838c2ecf20Sopenharmony_ci
36848c2ecf20Sopenharmony_ci		if (mtu < L2CAP_DEFAULT_MIN_MTU)
36858c2ecf20Sopenharmony_ci			result = L2CAP_CONF_UNACCEPT;
36868c2ecf20Sopenharmony_ci		else {
36878c2ecf20Sopenharmony_ci			chan->omtu = mtu;
36888c2ecf20Sopenharmony_ci			set_bit(CONF_MTU_DONE, &chan->conf_state);
36898c2ecf20Sopenharmony_ci		}
36908c2ecf20Sopenharmony_ci		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu, endptr - ptr);
36918c2ecf20Sopenharmony_ci
36928c2ecf20Sopenharmony_ci		if (remote_efs) {
36938c2ecf20Sopenharmony_ci			if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
36948c2ecf20Sopenharmony_ci			    efs.stype != L2CAP_SERV_NOTRAFIC &&
36958c2ecf20Sopenharmony_ci			    efs.stype != chan->local_stype) {
36968c2ecf20Sopenharmony_ci
36978c2ecf20Sopenharmony_ci				result = L2CAP_CONF_UNACCEPT;
36988c2ecf20Sopenharmony_ci
36998c2ecf20Sopenharmony_ci				if (chan->num_conf_req >= 1)
37008c2ecf20Sopenharmony_ci					return -ECONNREFUSED;
37018c2ecf20Sopenharmony_ci
37028c2ecf20Sopenharmony_ci				l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
37038c2ecf20Sopenharmony_ci						   sizeof(efs),
37048c2ecf20Sopenharmony_ci						   (unsigned long) &efs, endptr - ptr);
37058c2ecf20Sopenharmony_ci			} else {
37068c2ecf20Sopenharmony_ci				/* Send PENDING Conf Rsp */
37078c2ecf20Sopenharmony_ci				result = L2CAP_CONF_PENDING;
37088c2ecf20Sopenharmony_ci				set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
37098c2ecf20Sopenharmony_ci			}
37108c2ecf20Sopenharmony_ci		}
37118c2ecf20Sopenharmony_ci
37128c2ecf20Sopenharmony_ci		switch (rfc.mode) {
37138c2ecf20Sopenharmony_ci		case L2CAP_MODE_BASIC:
37148c2ecf20Sopenharmony_ci			chan->fcs = L2CAP_FCS_NONE;
37158c2ecf20Sopenharmony_ci			set_bit(CONF_MODE_DONE, &chan->conf_state);
37168c2ecf20Sopenharmony_ci			break;
37178c2ecf20Sopenharmony_ci
37188c2ecf20Sopenharmony_ci		case L2CAP_MODE_ERTM:
37198c2ecf20Sopenharmony_ci			if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
37208c2ecf20Sopenharmony_ci				chan->remote_tx_win = rfc.txwin_size;
37218c2ecf20Sopenharmony_ci			else
37228c2ecf20Sopenharmony_ci				rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
37238c2ecf20Sopenharmony_ci
37248c2ecf20Sopenharmony_ci			chan->remote_max_tx = rfc.max_transmit;
37258c2ecf20Sopenharmony_ci
37268c2ecf20Sopenharmony_ci			size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
37278c2ecf20Sopenharmony_ci				     chan->conn->mtu - L2CAP_EXT_HDR_SIZE -
37288c2ecf20Sopenharmony_ci				     L2CAP_SDULEN_SIZE - L2CAP_FCS_SIZE);
37298c2ecf20Sopenharmony_ci			rfc.max_pdu_size = cpu_to_le16(size);
37308c2ecf20Sopenharmony_ci			chan->remote_mps = size;
37318c2ecf20Sopenharmony_ci
37328c2ecf20Sopenharmony_ci			__l2cap_set_ertm_timeouts(chan, &rfc);
37338c2ecf20Sopenharmony_ci
37348c2ecf20Sopenharmony_ci			set_bit(CONF_MODE_DONE, &chan->conf_state);
37358c2ecf20Sopenharmony_ci
37368c2ecf20Sopenharmony_ci			l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
37378c2ecf20Sopenharmony_ci					   sizeof(rfc), (unsigned long) &rfc, endptr - ptr);
37388c2ecf20Sopenharmony_ci
37398c2ecf20Sopenharmony_ci			if (remote_efs &&
37408c2ecf20Sopenharmony_ci			    test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
37418c2ecf20Sopenharmony_ci				chan->remote_id = efs.id;
37428c2ecf20Sopenharmony_ci				chan->remote_stype = efs.stype;
37438c2ecf20Sopenharmony_ci				chan->remote_msdu = le16_to_cpu(efs.msdu);
37448c2ecf20Sopenharmony_ci				chan->remote_flush_to =
37458c2ecf20Sopenharmony_ci					le32_to_cpu(efs.flush_to);
37468c2ecf20Sopenharmony_ci				chan->remote_acc_lat =
37478c2ecf20Sopenharmony_ci					le32_to_cpu(efs.acc_lat);
37488c2ecf20Sopenharmony_ci				chan->remote_sdu_itime =
37498c2ecf20Sopenharmony_ci					le32_to_cpu(efs.sdu_itime);
37508c2ecf20Sopenharmony_ci				l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
37518c2ecf20Sopenharmony_ci						   sizeof(efs),
37528c2ecf20Sopenharmony_ci						   (unsigned long) &efs, endptr - ptr);
37538c2ecf20Sopenharmony_ci			}
37548c2ecf20Sopenharmony_ci			break;
37558c2ecf20Sopenharmony_ci
37568c2ecf20Sopenharmony_ci		case L2CAP_MODE_STREAMING:
37578c2ecf20Sopenharmony_ci			size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
37588c2ecf20Sopenharmony_ci				     chan->conn->mtu - L2CAP_EXT_HDR_SIZE -
37598c2ecf20Sopenharmony_ci				     L2CAP_SDULEN_SIZE - L2CAP_FCS_SIZE);
37608c2ecf20Sopenharmony_ci			rfc.max_pdu_size = cpu_to_le16(size);
37618c2ecf20Sopenharmony_ci			chan->remote_mps = size;
37628c2ecf20Sopenharmony_ci
37638c2ecf20Sopenharmony_ci			set_bit(CONF_MODE_DONE, &chan->conf_state);
37648c2ecf20Sopenharmony_ci
37658c2ecf20Sopenharmony_ci			l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
37668c2ecf20Sopenharmony_ci					   (unsigned long) &rfc, endptr - ptr);
37678c2ecf20Sopenharmony_ci
37688c2ecf20Sopenharmony_ci			break;
37698c2ecf20Sopenharmony_ci
37708c2ecf20Sopenharmony_ci		default:
37718c2ecf20Sopenharmony_ci			result = L2CAP_CONF_UNACCEPT;
37728c2ecf20Sopenharmony_ci
37738c2ecf20Sopenharmony_ci			memset(&rfc, 0, sizeof(rfc));
37748c2ecf20Sopenharmony_ci			rfc.mode = chan->mode;
37758c2ecf20Sopenharmony_ci		}
37768c2ecf20Sopenharmony_ci
37778c2ecf20Sopenharmony_ci		if (result == L2CAP_CONF_SUCCESS)
37788c2ecf20Sopenharmony_ci			set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
37798c2ecf20Sopenharmony_ci	}
37808c2ecf20Sopenharmony_ci	rsp->scid   = cpu_to_le16(chan->dcid);
37818c2ecf20Sopenharmony_ci	rsp->result = cpu_to_le16(result);
37828c2ecf20Sopenharmony_ci	rsp->flags  = cpu_to_le16(0);
37838c2ecf20Sopenharmony_ci
37848c2ecf20Sopenharmony_ci	return ptr - data;
37858c2ecf20Sopenharmony_ci}
37868c2ecf20Sopenharmony_ci
37878c2ecf20Sopenharmony_cistatic int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len,
37888c2ecf20Sopenharmony_ci				void *data, size_t size, u16 *result)
37898c2ecf20Sopenharmony_ci{
37908c2ecf20Sopenharmony_ci	struct l2cap_conf_req *req = data;
37918c2ecf20Sopenharmony_ci	void *ptr = req->data;
37928c2ecf20Sopenharmony_ci	void *endptr = data + size;
37938c2ecf20Sopenharmony_ci	int type, olen;
37948c2ecf20Sopenharmony_ci	unsigned long val;
37958c2ecf20Sopenharmony_ci	struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
37968c2ecf20Sopenharmony_ci	struct l2cap_conf_efs efs;
37978c2ecf20Sopenharmony_ci
37988c2ecf20Sopenharmony_ci	BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
37998c2ecf20Sopenharmony_ci
38008c2ecf20Sopenharmony_ci	while (len >= L2CAP_CONF_OPT_SIZE) {
38018c2ecf20Sopenharmony_ci		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
38028c2ecf20Sopenharmony_ci		if (len < 0)
38038c2ecf20Sopenharmony_ci			break;
38048c2ecf20Sopenharmony_ci
38058c2ecf20Sopenharmony_ci		switch (type) {
38068c2ecf20Sopenharmony_ci		case L2CAP_CONF_MTU:
38078c2ecf20Sopenharmony_ci			if (olen != 2)
38088c2ecf20Sopenharmony_ci				break;
38098c2ecf20Sopenharmony_ci			if (val < L2CAP_DEFAULT_MIN_MTU) {
38108c2ecf20Sopenharmony_ci				*result = L2CAP_CONF_UNACCEPT;
38118c2ecf20Sopenharmony_ci				chan->imtu = L2CAP_DEFAULT_MIN_MTU;
38128c2ecf20Sopenharmony_ci			} else
38138c2ecf20Sopenharmony_ci				chan->imtu = val;
38148c2ecf20Sopenharmony_ci			l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu,
38158c2ecf20Sopenharmony_ci					   endptr - ptr);
38168c2ecf20Sopenharmony_ci			break;
38178c2ecf20Sopenharmony_ci
38188c2ecf20Sopenharmony_ci		case L2CAP_CONF_FLUSH_TO:
38198c2ecf20Sopenharmony_ci			if (olen != 2)
38208c2ecf20Sopenharmony_ci				break;
38218c2ecf20Sopenharmony_ci			chan->flush_to = val;
38228c2ecf20Sopenharmony_ci			l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2,
38238c2ecf20Sopenharmony_ci					   chan->flush_to, endptr - ptr);
38248c2ecf20Sopenharmony_ci			break;
38258c2ecf20Sopenharmony_ci
38268c2ecf20Sopenharmony_ci		case L2CAP_CONF_RFC:
38278c2ecf20Sopenharmony_ci			if (olen != sizeof(rfc))
38288c2ecf20Sopenharmony_ci				break;
38298c2ecf20Sopenharmony_ci			memcpy(&rfc, (void *)val, olen);
38308c2ecf20Sopenharmony_ci			if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
38318c2ecf20Sopenharmony_ci			    rfc.mode != chan->mode)
38328c2ecf20Sopenharmony_ci				return -ECONNREFUSED;
38338c2ecf20Sopenharmony_ci			chan->fcs = 0;
38348c2ecf20Sopenharmony_ci			l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
38358c2ecf20Sopenharmony_ci					   (unsigned long) &rfc, endptr - ptr);
38368c2ecf20Sopenharmony_ci			break;
38378c2ecf20Sopenharmony_ci
38388c2ecf20Sopenharmony_ci		case L2CAP_CONF_EWS:
38398c2ecf20Sopenharmony_ci			if (olen != 2)
38408c2ecf20Sopenharmony_ci				break;
38418c2ecf20Sopenharmony_ci			chan->ack_win = min_t(u16, val, chan->ack_win);
38428c2ecf20Sopenharmony_ci			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
38438c2ecf20Sopenharmony_ci					   chan->tx_win, endptr - ptr);
38448c2ecf20Sopenharmony_ci			break;
38458c2ecf20Sopenharmony_ci
38468c2ecf20Sopenharmony_ci		case L2CAP_CONF_EFS:
38478c2ecf20Sopenharmony_ci			if (olen != sizeof(efs))
38488c2ecf20Sopenharmony_ci				break;
38498c2ecf20Sopenharmony_ci			memcpy(&efs, (void *)val, olen);
38508c2ecf20Sopenharmony_ci			if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
38518c2ecf20Sopenharmony_ci			    efs.stype != L2CAP_SERV_NOTRAFIC &&
38528c2ecf20Sopenharmony_ci			    efs.stype != chan->local_stype)
38538c2ecf20Sopenharmony_ci				return -ECONNREFUSED;
38548c2ecf20Sopenharmony_ci			l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
38558c2ecf20Sopenharmony_ci					   (unsigned long) &efs, endptr - ptr);
38568c2ecf20Sopenharmony_ci			break;
38578c2ecf20Sopenharmony_ci
38588c2ecf20Sopenharmony_ci		case L2CAP_CONF_FCS:
38598c2ecf20Sopenharmony_ci			if (olen != 1)
38608c2ecf20Sopenharmony_ci				break;
38618c2ecf20Sopenharmony_ci			if (*result == L2CAP_CONF_PENDING)
38628c2ecf20Sopenharmony_ci				if (val == L2CAP_FCS_NONE)
38638c2ecf20Sopenharmony_ci					set_bit(CONF_RECV_NO_FCS,
38648c2ecf20Sopenharmony_ci						&chan->conf_state);
38658c2ecf20Sopenharmony_ci			break;
38668c2ecf20Sopenharmony_ci		}
38678c2ecf20Sopenharmony_ci	}
38688c2ecf20Sopenharmony_ci
38698c2ecf20Sopenharmony_ci	if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
38708c2ecf20Sopenharmony_ci		return -ECONNREFUSED;
38718c2ecf20Sopenharmony_ci
38728c2ecf20Sopenharmony_ci	chan->mode = rfc.mode;
38738c2ecf20Sopenharmony_ci
38748c2ecf20Sopenharmony_ci	if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
38758c2ecf20Sopenharmony_ci		switch (rfc.mode) {
38768c2ecf20Sopenharmony_ci		case L2CAP_MODE_ERTM:
38778c2ecf20Sopenharmony_ci			chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
38788c2ecf20Sopenharmony_ci			chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
38798c2ecf20Sopenharmony_ci			chan->mps    = le16_to_cpu(rfc.max_pdu_size);
38808c2ecf20Sopenharmony_ci			if (!test_bit(FLAG_EXT_CTRL, &chan->flags))
38818c2ecf20Sopenharmony_ci				chan->ack_win = min_t(u16, chan->ack_win,
38828c2ecf20Sopenharmony_ci						      rfc.txwin_size);
38838c2ecf20Sopenharmony_ci
38848c2ecf20Sopenharmony_ci			if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
38858c2ecf20Sopenharmony_ci				chan->local_msdu = le16_to_cpu(efs.msdu);
38868c2ecf20Sopenharmony_ci				chan->local_sdu_itime =
38878c2ecf20Sopenharmony_ci					le32_to_cpu(efs.sdu_itime);
38888c2ecf20Sopenharmony_ci				chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
38898c2ecf20Sopenharmony_ci				chan->local_flush_to =
38908c2ecf20Sopenharmony_ci					le32_to_cpu(efs.flush_to);
38918c2ecf20Sopenharmony_ci			}
38928c2ecf20Sopenharmony_ci			break;
38938c2ecf20Sopenharmony_ci
38948c2ecf20Sopenharmony_ci		case L2CAP_MODE_STREAMING:
38958c2ecf20Sopenharmony_ci			chan->mps    = le16_to_cpu(rfc.max_pdu_size);
38968c2ecf20Sopenharmony_ci		}
38978c2ecf20Sopenharmony_ci	}
38988c2ecf20Sopenharmony_ci
38998c2ecf20Sopenharmony_ci	req->dcid   = cpu_to_le16(chan->dcid);
39008c2ecf20Sopenharmony_ci	req->flags  = cpu_to_le16(0);
39018c2ecf20Sopenharmony_ci
39028c2ecf20Sopenharmony_ci	return ptr - data;
39038c2ecf20Sopenharmony_ci}
39048c2ecf20Sopenharmony_ci
39058c2ecf20Sopenharmony_cistatic int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data,
39068c2ecf20Sopenharmony_ci				u16 result, u16 flags)
39078c2ecf20Sopenharmony_ci{
39088c2ecf20Sopenharmony_ci	struct l2cap_conf_rsp *rsp = data;
39098c2ecf20Sopenharmony_ci	void *ptr = rsp->data;
39108c2ecf20Sopenharmony_ci
39118c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
39128c2ecf20Sopenharmony_ci
39138c2ecf20Sopenharmony_ci	rsp->scid   = cpu_to_le16(chan->dcid);
39148c2ecf20Sopenharmony_ci	rsp->result = cpu_to_le16(result);
39158c2ecf20Sopenharmony_ci	rsp->flags  = cpu_to_le16(flags);
39168c2ecf20Sopenharmony_ci
39178c2ecf20Sopenharmony_ci	return ptr - data;
39188c2ecf20Sopenharmony_ci}
39198c2ecf20Sopenharmony_ci
39208c2ecf20Sopenharmony_civoid __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan)
39218c2ecf20Sopenharmony_ci{
39228c2ecf20Sopenharmony_ci	struct l2cap_le_conn_rsp rsp;
39238c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
39248c2ecf20Sopenharmony_ci
39258c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
39268c2ecf20Sopenharmony_ci
39278c2ecf20Sopenharmony_ci	rsp.dcid    = cpu_to_le16(chan->scid);
39288c2ecf20Sopenharmony_ci	rsp.mtu     = cpu_to_le16(chan->imtu);
39298c2ecf20Sopenharmony_ci	rsp.mps     = cpu_to_le16(chan->mps);
39308c2ecf20Sopenharmony_ci	rsp.credits = cpu_to_le16(chan->rx_credits);
39318c2ecf20Sopenharmony_ci	rsp.result  = cpu_to_le16(L2CAP_CR_LE_SUCCESS);
39328c2ecf20Sopenharmony_ci
39338c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CONN_RSP, sizeof(rsp),
39348c2ecf20Sopenharmony_ci		       &rsp);
39358c2ecf20Sopenharmony_ci}
39368c2ecf20Sopenharmony_ci
39378c2ecf20Sopenharmony_cistatic void l2cap_ecred_list_defer(struct l2cap_chan *chan, void *data)
39388c2ecf20Sopenharmony_ci{
39398c2ecf20Sopenharmony_ci	int *result = data;
39408c2ecf20Sopenharmony_ci
39418c2ecf20Sopenharmony_ci	if (*result || test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
39428c2ecf20Sopenharmony_ci		return;
39438c2ecf20Sopenharmony_ci
39448c2ecf20Sopenharmony_ci	switch (chan->state) {
39458c2ecf20Sopenharmony_ci	case BT_CONNECT2:
39468c2ecf20Sopenharmony_ci		/* If channel still pending accept add to result */
39478c2ecf20Sopenharmony_ci		(*result)++;
39488c2ecf20Sopenharmony_ci		return;
39498c2ecf20Sopenharmony_ci	case BT_CONNECTED:
39508c2ecf20Sopenharmony_ci		return;
39518c2ecf20Sopenharmony_ci	default:
39528c2ecf20Sopenharmony_ci		/* If not connected or pending accept it has been refused */
39538c2ecf20Sopenharmony_ci		*result = -ECONNREFUSED;
39548c2ecf20Sopenharmony_ci		return;
39558c2ecf20Sopenharmony_ci	}
39568c2ecf20Sopenharmony_ci}
39578c2ecf20Sopenharmony_ci
39588c2ecf20Sopenharmony_cistruct l2cap_ecred_rsp_data {
39598c2ecf20Sopenharmony_ci	struct {
39608c2ecf20Sopenharmony_ci		struct l2cap_ecred_conn_rsp rsp;
39618c2ecf20Sopenharmony_ci		__le16 scid[L2CAP_ECRED_MAX_CID];
39628c2ecf20Sopenharmony_ci	} __packed pdu;
39638c2ecf20Sopenharmony_ci	int count;
39648c2ecf20Sopenharmony_ci};
39658c2ecf20Sopenharmony_ci
39668c2ecf20Sopenharmony_cistatic void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data)
39678c2ecf20Sopenharmony_ci{
39688c2ecf20Sopenharmony_ci	struct l2cap_ecred_rsp_data *rsp = data;
39698c2ecf20Sopenharmony_ci
39708c2ecf20Sopenharmony_ci	if (test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
39718c2ecf20Sopenharmony_ci		return;
39728c2ecf20Sopenharmony_ci
39738c2ecf20Sopenharmony_ci	/* Reset ident so only one response is sent */
39748c2ecf20Sopenharmony_ci	chan->ident = 0;
39758c2ecf20Sopenharmony_ci
39768c2ecf20Sopenharmony_ci	/* Include all channels pending with the same ident */
39778c2ecf20Sopenharmony_ci	if (!rsp->pdu.rsp.result)
39788c2ecf20Sopenharmony_ci		rsp->pdu.rsp.dcid[rsp->count++] = cpu_to_le16(chan->scid);
39798c2ecf20Sopenharmony_ci	else
39808c2ecf20Sopenharmony_ci		l2cap_chan_del(chan, ECONNRESET);
39818c2ecf20Sopenharmony_ci}
39828c2ecf20Sopenharmony_ci
39838c2ecf20Sopenharmony_civoid __l2cap_ecred_conn_rsp_defer(struct l2cap_chan *chan)
39848c2ecf20Sopenharmony_ci{
39858c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
39868c2ecf20Sopenharmony_ci	struct l2cap_ecred_rsp_data data;
39878c2ecf20Sopenharmony_ci	u16 id = chan->ident;
39888c2ecf20Sopenharmony_ci	int result = 0;
39898c2ecf20Sopenharmony_ci
39908c2ecf20Sopenharmony_ci	if (!id)
39918c2ecf20Sopenharmony_ci		return;
39928c2ecf20Sopenharmony_ci
39938c2ecf20Sopenharmony_ci	BT_DBG("chan %p id %d", chan, id);
39948c2ecf20Sopenharmony_ci
39958c2ecf20Sopenharmony_ci	memset(&data, 0, sizeof(data));
39968c2ecf20Sopenharmony_ci
39978c2ecf20Sopenharmony_ci	data.pdu.rsp.mtu     = cpu_to_le16(chan->imtu);
39988c2ecf20Sopenharmony_ci	data.pdu.rsp.mps     = cpu_to_le16(chan->mps);
39998c2ecf20Sopenharmony_ci	data.pdu.rsp.credits = cpu_to_le16(chan->rx_credits);
40008c2ecf20Sopenharmony_ci	data.pdu.rsp.result  = cpu_to_le16(L2CAP_CR_LE_SUCCESS);
40018c2ecf20Sopenharmony_ci
40028c2ecf20Sopenharmony_ci	/* Verify that all channels are ready */
40038c2ecf20Sopenharmony_ci	__l2cap_chan_list_id(conn, id, l2cap_ecred_list_defer, &result);
40048c2ecf20Sopenharmony_ci
40058c2ecf20Sopenharmony_ci	if (result > 0)
40068c2ecf20Sopenharmony_ci		return;
40078c2ecf20Sopenharmony_ci
40088c2ecf20Sopenharmony_ci	if (result < 0)
40098c2ecf20Sopenharmony_ci		data.pdu.rsp.result = cpu_to_le16(L2CAP_CR_LE_AUTHORIZATION);
40108c2ecf20Sopenharmony_ci
40118c2ecf20Sopenharmony_ci	/* Build response */
40128c2ecf20Sopenharmony_ci	__l2cap_chan_list_id(conn, id, l2cap_ecred_rsp_defer, &data);
40138c2ecf20Sopenharmony_ci
40148c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, id, L2CAP_ECRED_CONN_RSP,
40158c2ecf20Sopenharmony_ci		       sizeof(data.pdu.rsp) + (data.count * sizeof(__le16)),
40168c2ecf20Sopenharmony_ci		       &data.pdu);
40178c2ecf20Sopenharmony_ci}
40188c2ecf20Sopenharmony_ci
40198c2ecf20Sopenharmony_civoid __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
40208c2ecf20Sopenharmony_ci{
40218c2ecf20Sopenharmony_ci	struct l2cap_conn_rsp rsp;
40228c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
40238c2ecf20Sopenharmony_ci	u8 buf[128];
40248c2ecf20Sopenharmony_ci	u8 rsp_code;
40258c2ecf20Sopenharmony_ci
40268c2ecf20Sopenharmony_ci	rsp.scid   = cpu_to_le16(chan->dcid);
40278c2ecf20Sopenharmony_ci	rsp.dcid   = cpu_to_le16(chan->scid);
40288c2ecf20Sopenharmony_ci	rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
40298c2ecf20Sopenharmony_ci	rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
40308c2ecf20Sopenharmony_ci
40318c2ecf20Sopenharmony_ci	if (chan->hs_hcon)
40328c2ecf20Sopenharmony_ci		rsp_code = L2CAP_CREATE_CHAN_RSP;
40338c2ecf20Sopenharmony_ci	else
40348c2ecf20Sopenharmony_ci		rsp_code = L2CAP_CONN_RSP;
40358c2ecf20Sopenharmony_ci
40368c2ecf20Sopenharmony_ci	BT_DBG("chan %p rsp_code %u", chan, rsp_code);
40378c2ecf20Sopenharmony_ci
40388c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, chan->ident, rsp_code, sizeof(rsp), &rsp);
40398c2ecf20Sopenharmony_ci
40408c2ecf20Sopenharmony_ci	if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
40418c2ecf20Sopenharmony_ci		return;
40428c2ecf20Sopenharmony_ci
40438c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
40448c2ecf20Sopenharmony_ci		       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
40458c2ecf20Sopenharmony_ci	chan->num_conf_req++;
40468c2ecf20Sopenharmony_ci}
40478c2ecf20Sopenharmony_ci
40488c2ecf20Sopenharmony_cistatic void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
40498c2ecf20Sopenharmony_ci{
40508c2ecf20Sopenharmony_ci	int type, olen;
40518c2ecf20Sopenharmony_ci	unsigned long val;
40528c2ecf20Sopenharmony_ci	/* Use sane default values in case a misbehaving remote device
40538c2ecf20Sopenharmony_ci	 * did not send an RFC or extended window size option.
40548c2ecf20Sopenharmony_ci	 */
40558c2ecf20Sopenharmony_ci	u16 txwin_ext = chan->ack_win;
40568c2ecf20Sopenharmony_ci	struct l2cap_conf_rfc rfc = {
40578c2ecf20Sopenharmony_ci		.mode = chan->mode,
40588c2ecf20Sopenharmony_ci		.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO),
40598c2ecf20Sopenharmony_ci		.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO),
40608c2ecf20Sopenharmony_ci		.max_pdu_size = cpu_to_le16(chan->imtu),
40618c2ecf20Sopenharmony_ci		.txwin_size = min_t(u16, chan->ack_win, L2CAP_DEFAULT_TX_WINDOW),
40628c2ecf20Sopenharmony_ci	};
40638c2ecf20Sopenharmony_ci
40648c2ecf20Sopenharmony_ci	BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
40658c2ecf20Sopenharmony_ci
40668c2ecf20Sopenharmony_ci	if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
40678c2ecf20Sopenharmony_ci		return;
40688c2ecf20Sopenharmony_ci
40698c2ecf20Sopenharmony_ci	while (len >= L2CAP_CONF_OPT_SIZE) {
40708c2ecf20Sopenharmony_ci		len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
40718c2ecf20Sopenharmony_ci		if (len < 0)
40728c2ecf20Sopenharmony_ci			break;
40738c2ecf20Sopenharmony_ci
40748c2ecf20Sopenharmony_ci		switch (type) {
40758c2ecf20Sopenharmony_ci		case L2CAP_CONF_RFC:
40768c2ecf20Sopenharmony_ci			if (olen != sizeof(rfc))
40778c2ecf20Sopenharmony_ci				break;
40788c2ecf20Sopenharmony_ci			memcpy(&rfc, (void *)val, olen);
40798c2ecf20Sopenharmony_ci			break;
40808c2ecf20Sopenharmony_ci		case L2CAP_CONF_EWS:
40818c2ecf20Sopenharmony_ci			if (olen != 2)
40828c2ecf20Sopenharmony_ci				break;
40838c2ecf20Sopenharmony_ci			txwin_ext = val;
40848c2ecf20Sopenharmony_ci			break;
40858c2ecf20Sopenharmony_ci		}
40868c2ecf20Sopenharmony_ci	}
40878c2ecf20Sopenharmony_ci
40888c2ecf20Sopenharmony_ci	switch (rfc.mode) {
40898c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
40908c2ecf20Sopenharmony_ci		chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
40918c2ecf20Sopenharmony_ci		chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
40928c2ecf20Sopenharmony_ci		chan->mps = le16_to_cpu(rfc.max_pdu_size);
40938c2ecf20Sopenharmony_ci		if (test_bit(FLAG_EXT_CTRL, &chan->flags))
40948c2ecf20Sopenharmony_ci			chan->ack_win = min_t(u16, chan->ack_win, txwin_ext);
40958c2ecf20Sopenharmony_ci		else
40968c2ecf20Sopenharmony_ci			chan->ack_win = min_t(u16, chan->ack_win,
40978c2ecf20Sopenharmony_ci					      rfc.txwin_size);
40988c2ecf20Sopenharmony_ci		break;
40998c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
41008c2ecf20Sopenharmony_ci		chan->mps    = le16_to_cpu(rfc.max_pdu_size);
41018c2ecf20Sopenharmony_ci	}
41028c2ecf20Sopenharmony_ci}
41038c2ecf20Sopenharmony_ci
41048c2ecf20Sopenharmony_cistatic inline int l2cap_command_rej(struct l2cap_conn *conn,
41058c2ecf20Sopenharmony_ci				    struct l2cap_cmd_hdr *cmd, u16 cmd_len,
41068c2ecf20Sopenharmony_ci				    u8 *data)
41078c2ecf20Sopenharmony_ci{
41088c2ecf20Sopenharmony_ci	struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
41098c2ecf20Sopenharmony_ci
41108c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*rej))
41118c2ecf20Sopenharmony_ci		return -EPROTO;
41128c2ecf20Sopenharmony_ci
41138c2ecf20Sopenharmony_ci	if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
41148c2ecf20Sopenharmony_ci		return 0;
41158c2ecf20Sopenharmony_ci
41168c2ecf20Sopenharmony_ci	if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
41178c2ecf20Sopenharmony_ci	    cmd->ident == conn->info_ident) {
41188c2ecf20Sopenharmony_ci		cancel_delayed_work(&conn->info_timer);
41198c2ecf20Sopenharmony_ci
41208c2ecf20Sopenharmony_ci		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
41218c2ecf20Sopenharmony_ci		conn->info_ident = 0;
41228c2ecf20Sopenharmony_ci
41238c2ecf20Sopenharmony_ci		l2cap_conn_start(conn);
41248c2ecf20Sopenharmony_ci	}
41258c2ecf20Sopenharmony_ci
41268c2ecf20Sopenharmony_ci	return 0;
41278c2ecf20Sopenharmony_ci}
41288c2ecf20Sopenharmony_ci
41298c2ecf20Sopenharmony_cistatic struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
41308c2ecf20Sopenharmony_ci					struct l2cap_cmd_hdr *cmd,
41318c2ecf20Sopenharmony_ci					u8 *data, u8 rsp_code, u8 amp_id)
41328c2ecf20Sopenharmony_ci{
41338c2ecf20Sopenharmony_ci	struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
41348c2ecf20Sopenharmony_ci	struct l2cap_conn_rsp rsp;
41358c2ecf20Sopenharmony_ci	struct l2cap_chan *chan = NULL, *pchan;
41368c2ecf20Sopenharmony_ci	int result, status = L2CAP_CS_NO_INFO;
41378c2ecf20Sopenharmony_ci
41388c2ecf20Sopenharmony_ci	u16 dcid = 0, scid = __le16_to_cpu(req->scid);
41398c2ecf20Sopenharmony_ci	__le16 psm = req->psm;
41408c2ecf20Sopenharmony_ci
41418c2ecf20Sopenharmony_ci	BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid);
41428c2ecf20Sopenharmony_ci
41438c2ecf20Sopenharmony_ci	/* Check if we have socket listening on psm */
41448c2ecf20Sopenharmony_ci	pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src,
41458c2ecf20Sopenharmony_ci					 &conn->hcon->dst, ACL_LINK);
41468c2ecf20Sopenharmony_ci	if (!pchan) {
41478c2ecf20Sopenharmony_ci		result = L2CAP_CR_BAD_PSM;
41488c2ecf20Sopenharmony_ci		goto sendresp;
41498c2ecf20Sopenharmony_ci	}
41508c2ecf20Sopenharmony_ci
41518c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
41528c2ecf20Sopenharmony_ci	l2cap_chan_lock(pchan);
41538c2ecf20Sopenharmony_ci
41548c2ecf20Sopenharmony_ci	/* Check if the ACL is secure enough (if not SDP) */
41558c2ecf20Sopenharmony_ci	if (psm != cpu_to_le16(L2CAP_PSM_SDP) &&
41568c2ecf20Sopenharmony_ci	    !hci_conn_check_link_mode(conn->hcon)) {
41578c2ecf20Sopenharmony_ci		conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
41588c2ecf20Sopenharmony_ci		result = L2CAP_CR_SEC_BLOCK;
41598c2ecf20Sopenharmony_ci		goto response;
41608c2ecf20Sopenharmony_ci	}
41618c2ecf20Sopenharmony_ci
41628c2ecf20Sopenharmony_ci	result = L2CAP_CR_NO_MEM;
41638c2ecf20Sopenharmony_ci
41648c2ecf20Sopenharmony_ci	/* Check for valid dynamic CID range (as per Erratum 3253) */
41658c2ecf20Sopenharmony_ci	if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_DYN_END) {
41668c2ecf20Sopenharmony_ci		result = L2CAP_CR_INVALID_SCID;
41678c2ecf20Sopenharmony_ci		goto response;
41688c2ecf20Sopenharmony_ci	}
41698c2ecf20Sopenharmony_ci
41708c2ecf20Sopenharmony_ci	/* Check if we already have channel with that dcid */
41718c2ecf20Sopenharmony_ci	if (__l2cap_get_chan_by_dcid(conn, scid)) {
41728c2ecf20Sopenharmony_ci		result = L2CAP_CR_SCID_IN_USE;
41738c2ecf20Sopenharmony_ci		goto response;
41748c2ecf20Sopenharmony_ci	}
41758c2ecf20Sopenharmony_ci
41768c2ecf20Sopenharmony_ci	chan = pchan->ops->new_connection(pchan);
41778c2ecf20Sopenharmony_ci	if (!chan)
41788c2ecf20Sopenharmony_ci		goto response;
41798c2ecf20Sopenharmony_ci
41808c2ecf20Sopenharmony_ci	/* For certain devices (ex: HID mouse), support for authentication,
41818c2ecf20Sopenharmony_ci	 * pairing and bonding is optional. For such devices, inorder to avoid
41828c2ecf20Sopenharmony_ci	 * the ACL alive for too long after L2CAP disconnection, reset the ACL
41838c2ecf20Sopenharmony_ci	 * disc_timeout back to HCI_DISCONN_TIMEOUT during L2CAP connect.
41848c2ecf20Sopenharmony_ci	 */
41858c2ecf20Sopenharmony_ci	conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
41868c2ecf20Sopenharmony_ci
41878c2ecf20Sopenharmony_ci	bacpy(&chan->src, &conn->hcon->src);
41888c2ecf20Sopenharmony_ci	bacpy(&chan->dst, &conn->hcon->dst);
41898c2ecf20Sopenharmony_ci	chan->src_type = bdaddr_src_type(conn->hcon);
41908c2ecf20Sopenharmony_ci	chan->dst_type = bdaddr_dst_type(conn->hcon);
41918c2ecf20Sopenharmony_ci	chan->psm  = psm;
41928c2ecf20Sopenharmony_ci	chan->dcid = scid;
41938c2ecf20Sopenharmony_ci	chan->local_amp_id = amp_id;
41948c2ecf20Sopenharmony_ci
41958c2ecf20Sopenharmony_ci	__l2cap_chan_add(conn, chan);
41968c2ecf20Sopenharmony_ci
41978c2ecf20Sopenharmony_ci	dcid = chan->scid;
41988c2ecf20Sopenharmony_ci
41998c2ecf20Sopenharmony_ci	__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
42008c2ecf20Sopenharmony_ci
42018c2ecf20Sopenharmony_ci	chan->ident = cmd->ident;
42028c2ecf20Sopenharmony_ci
42038c2ecf20Sopenharmony_ci	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
42048c2ecf20Sopenharmony_ci		if (l2cap_chan_check_security(chan, false)) {
42058c2ecf20Sopenharmony_ci			if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
42068c2ecf20Sopenharmony_ci				l2cap_state_change(chan, BT_CONNECT2);
42078c2ecf20Sopenharmony_ci				result = L2CAP_CR_PEND;
42088c2ecf20Sopenharmony_ci				status = L2CAP_CS_AUTHOR_PEND;
42098c2ecf20Sopenharmony_ci				chan->ops->defer(chan);
42108c2ecf20Sopenharmony_ci			} else {
42118c2ecf20Sopenharmony_ci				/* Force pending result for AMP controllers.
42128c2ecf20Sopenharmony_ci				 * The connection will succeed after the
42138c2ecf20Sopenharmony_ci				 * physical link is up.
42148c2ecf20Sopenharmony_ci				 */
42158c2ecf20Sopenharmony_ci				if (amp_id == AMP_ID_BREDR) {
42168c2ecf20Sopenharmony_ci					l2cap_state_change(chan, BT_CONFIG);
42178c2ecf20Sopenharmony_ci					result = L2CAP_CR_SUCCESS;
42188c2ecf20Sopenharmony_ci				} else {
42198c2ecf20Sopenharmony_ci					l2cap_state_change(chan, BT_CONNECT2);
42208c2ecf20Sopenharmony_ci					result = L2CAP_CR_PEND;
42218c2ecf20Sopenharmony_ci				}
42228c2ecf20Sopenharmony_ci				status = L2CAP_CS_NO_INFO;
42238c2ecf20Sopenharmony_ci			}
42248c2ecf20Sopenharmony_ci		} else {
42258c2ecf20Sopenharmony_ci			l2cap_state_change(chan, BT_CONNECT2);
42268c2ecf20Sopenharmony_ci			result = L2CAP_CR_PEND;
42278c2ecf20Sopenharmony_ci			status = L2CAP_CS_AUTHEN_PEND;
42288c2ecf20Sopenharmony_ci		}
42298c2ecf20Sopenharmony_ci	} else {
42308c2ecf20Sopenharmony_ci		l2cap_state_change(chan, BT_CONNECT2);
42318c2ecf20Sopenharmony_ci		result = L2CAP_CR_PEND;
42328c2ecf20Sopenharmony_ci		status = L2CAP_CS_NO_INFO;
42338c2ecf20Sopenharmony_ci	}
42348c2ecf20Sopenharmony_ci
42358c2ecf20Sopenharmony_ciresponse:
42368c2ecf20Sopenharmony_ci	l2cap_chan_unlock(pchan);
42378c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
42388c2ecf20Sopenharmony_ci	l2cap_chan_put(pchan);
42398c2ecf20Sopenharmony_ci
42408c2ecf20Sopenharmony_cisendresp:
42418c2ecf20Sopenharmony_ci	rsp.scid   = cpu_to_le16(scid);
42428c2ecf20Sopenharmony_ci	rsp.dcid   = cpu_to_le16(dcid);
42438c2ecf20Sopenharmony_ci	rsp.result = cpu_to_le16(result);
42448c2ecf20Sopenharmony_ci	rsp.status = cpu_to_le16(status);
42458c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, cmd->ident, rsp_code, sizeof(rsp), &rsp);
42468c2ecf20Sopenharmony_ci
42478c2ecf20Sopenharmony_ci	if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
42488c2ecf20Sopenharmony_ci		struct l2cap_info_req info;
42498c2ecf20Sopenharmony_ci		info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
42508c2ecf20Sopenharmony_ci
42518c2ecf20Sopenharmony_ci		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
42528c2ecf20Sopenharmony_ci		conn->info_ident = l2cap_get_ident(conn);
42538c2ecf20Sopenharmony_ci
42548c2ecf20Sopenharmony_ci		schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
42558c2ecf20Sopenharmony_ci
42568c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ,
42578c2ecf20Sopenharmony_ci			       sizeof(info), &info);
42588c2ecf20Sopenharmony_ci	}
42598c2ecf20Sopenharmony_ci
42608c2ecf20Sopenharmony_ci	if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
42618c2ecf20Sopenharmony_ci	    result == L2CAP_CR_SUCCESS) {
42628c2ecf20Sopenharmony_ci		u8 buf[128];
42638c2ecf20Sopenharmony_ci		set_bit(CONF_REQ_SENT, &chan->conf_state);
42648c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
42658c2ecf20Sopenharmony_ci			       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
42668c2ecf20Sopenharmony_ci		chan->num_conf_req++;
42678c2ecf20Sopenharmony_ci	}
42688c2ecf20Sopenharmony_ci
42698c2ecf20Sopenharmony_ci	return chan;
42708c2ecf20Sopenharmony_ci}
42718c2ecf20Sopenharmony_ci
42728c2ecf20Sopenharmony_cistatic int l2cap_connect_req(struct l2cap_conn *conn,
42738c2ecf20Sopenharmony_ci			     struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
42748c2ecf20Sopenharmony_ci{
42758c2ecf20Sopenharmony_ci	struct hci_dev *hdev = conn->hcon->hdev;
42768c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
42778c2ecf20Sopenharmony_ci
42788c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(struct l2cap_conn_req))
42798c2ecf20Sopenharmony_ci		return -EPROTO;
42808c2ecf20Sopenharmony_ci
42818c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
42828c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_MGMT) &&
42838c2ecf20Sopenharmony_ci	    !test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &hcon->flags))
42848c2ecf20Sopenharmony_ci		mgmt_device_connected(hdev, hcon, 0, NULL, 0);
42858c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
42868c2ecf20Sopenharmony_ci
42878c2ecf20Sopenharmony_ci	l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
42888c2ecf20Sopenharmony_ci	return 0;
42898c2ecf20Sopenharmony_ci}
42908c2ecf20Sopenharmony_ci
42918c2ecf20Sopenharmony_cistatic int l2cap_connect_create_rsp(struct l2cap_conn *conn,
42928c2ecf20Sopenharmony_ci				    struct l2cap_cmd_hdr *cmd, u16 cmd_len,
42938c2ecf20Sopenharmony_ci				    u8 *data)
42948c2ecf20Sopenharmony_ci{
42958c2ecf20Sopenharmony_ci	struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
42968c2ecf20Sopenharmony_ci	u16 scid, dcid, result, status;
42978c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
42988c2ecf20Sopenharmony_ci	u8 req[128];
42998c2ecf20Sopenharmony_ci	int err;
43008c2ecf20Sopenharmony_ci
43018c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*rsp))
43028c2ecf20Sopenharmony_ci		return -EPROTO;
43038c2ecf20Sopenharmony_ci
43048c2ecf20Sopenharmony_ci	scid   = __le16_to_cpu(rsp->scid);
43058c2ecf20Sopenharmony_ci	dcid   = __le16_to_cpu(rsp->dcid);
43068c2ecf20Sopenharmony_ci	result = __le16_to_cpu(rsp->result);
43078c2ecf20Sopenharmony_ci	status = __le16_to_cpu(rsp->status);
43088c2ecf20Sopenharmony_ci
43098c2ecf20Sopenharmony_ci	if (result == L2CAP_CR_SUCCESS && (dcid < L2CAP_CID_DYN_START ||
43108c2ecf20Sopenharmony_ci					   dcid > L2CAP_CID_DYN_END))
43118c2ecf20Sopenharmony_ci		return -EPROTO;
43128c2ecf20Sopenharmony_ci
43138c2ecf20Sopenharmony_ci	BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
43148c2ecf20Sopenharmony_ci	       dcid, scid, result, status);
43158c2ecf20Sopenharmony_ci
43168c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
43178c2ecf20Sopenharmony_ci
43188c2ecf20Sopenharmony_ci	if (scid) {
43198c2ecf20Sopenharmony_ci		chan = __l2cap_get_chan_by_scid(conn, scid);
43208c2ecf20Sopenharmony_ci		if (!chan) {
43218c2ecf20Sopenharmony_ci			err = -EBADSLT;
43228c2ecf20Sopenharmony_ci			goto unlock;
43238c2ecf20Sopenharmony_ci		}
43248c2ecf20Sopenharmony_ci	} else {
43258c2ecf20Sopenharmony_ci		chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
43268c2ecf20Sopenharmony_ci		if (!chan) {
43278c2ecf20Sopenharmony_ci			err = -EBADSLT;
43288c2ecf20Sopenharmony_ci			goto unlock;
43298c2ecf20Sopenharmony_ci		}
43308c2ecf20Sopenharmony_ci	}
43318c2ecf20Sopenharmony_ci
43328c2ecf20Sopenharmony_ci	chan = l2cap_chan_hold_unless_zero(chan);
43338c2ecf20Sopenharmony_ci	if (!chan) {
43348c2ecf20Sopenharmony_ci		err = -EBADSLT;
43358c2ecf20Sopenharmony_ci		goto unlock;
43368c2ecf20Sopenharmony_ci	}
43378c2ecf20Sopenharmony_ci
43388c2ecf20Sopenharmony_ci	err = 0;
43398c2ecf20Sopenharmony_ci
43408c2ecf20Sopenharmony_ci	l2cap_chan_lock(chan);
43418c2ecf20Sopenharmony_ci
43428c2ecf20Sopenharmony_ci	switch (result) {
43438c2ecf20Sopenharmony_ci	case L2CAP_CR_SUCCESS:
43448c2ecf20Sopenharmony_ci		if (__l2cap_get_chan_by_dcid(conn, dcid)) {
43458c2ecf20Sopenharmony_ci			err = -EBADSLT;
43468c2ecf20Sopenharmony_ci			break;
43478c2ecf20Sopenharmony_ci		}
43488c2ecf20Sopenharmony_ci
43498c2ecf20Sopenharmony_ci		l2cap_state_change(chan, BT_CONFIG);
43508c2ecf20Sopenharmony_ci		chan->ident = 0;
43518c2ecf20Sopenharmony_ci		chan->dcid = dcid;
43528c2ecf20Sopenharmony_ci		clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
43538c2ecf20Sopenharmony_ci
43548c2ecf20Sopenharmony_ci		if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
43558c2ecf20Sopenharmony_ci			break;
43568c2ecf20Sopenharmony_ci
43578c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
43588c2ecf20Sopenharmony_ci			       l2cap_build_conf_req(chan, req, sizeof(req)), req);
43598c2ecf20Sopenharmony_ci		chan->num_conf_req++;
43608c2ecf20Sopenharmony_ci		break;
43618c2ecf20Sopenharmony_ci
43628c2ecf20Sopenharmony_ci	case L2CAP_CR_PEND:
43638c2ecf20Sopenharmony_ci		set_bit(CONF_CONNECT_PEND, &chan->conf_state);
43648c2ecf20Sopenharmony_ci		break;
43658c2ecf20Sopenharmony_ci
43668c2ecf20Sopenharmony_ci	default:
43678c2ecf20Sopenharmony_ci		l2cap_chan_del(chan, ECONNREFUSED);
43688c2ecf20Sopenharmony_ci		break;
43698c2ecf20Sopenharmony_ci	}
43708c2ecf20Sopenharmony_ci
43718c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
43728c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
43738c2ecf20Sopenharmony_ci
43748c2ecf20Sopenharmony_ciunlock:
43758c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
43768c2ecf20Sopenharmony_ci
43778c2ecf20Sopenharmony_ci	return err;
43788c2ecf20Sopenharmony_ci}
43798c2ecf20Sopenharmony_ci
43808c2ecf20Sopenharmony_cistatic inline void set_default_fcs(struct l2cap_chan *chan)
43818c2ecf20Sopenharmony_ci{
43828c2ecf20Sopenharmony_ci	/* FCS is enabled only in ERTM or streaming mode, if one or both
43838c2ecf20Sopenharmony_ci	 * sides request it.
43848c2ecf20Sopenharmony_ci	 */
43858c2ecf20Sopenharmony_ci	if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
43868c2ecf20Sopenharmony_ci		chan->fcs = L2CAP_FCS_NONE;
43878c2ecf20Sopenharmony_ci	else if (!test_bit(CONF_RECV_NO_FCS, &chan->conf_state))
43888c2ecf20Sopenharmony_ci		chan->fcs = L2CAP_FCS_CRC16;
43898c2ecf20Sopenharmony_ci}
43908c2ecf20Sopenharmony_ci
43918c2ecf20Sopenharmony_cistatic void l2cap_send_efs_conf_rsp(struct l2cap_chan *chan, void *data,
43928c2ecf20Sopenharmony_ci				    u8 ident, u16 flags)
43938c2ecf20Sopenharmony_ci{
43948c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
43958c2ecf20Sopenharmony_ci
43968c2ecf20Sopenharmony_ci	BT_DBG("conn %p chan %p ident %d flags 0x%4.4x", conn, chan, ident,
43978c2ecf20Sopenharmony_ci	       flags);
43988c2ecf20Sopenharmony_ci
43998c2ecf20Sopenharmony_ci	clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
44008c2ecf20Sopenharmony_ci	set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
44018c2ecf20Sopenharmony_ci
44028c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, ident, L2CAP_CONF_RSP,
44038c2ecf20Sopenharmony_ci		       l2cap_build_conf_rsp(chan, data,
44048c2ecf20Sopenharmony_ci					    L2CAP_CONF_SUCCESS, flags), data);
44058c2ecf20Sopenharmony_ci}
44068c2ecf20Sopenharmony_ci
44078c2ecf20Sopenharmony_cistatic void cmd_reject_invalid_cid(struct l2cap_conn *conn, u8 ident,
44088c2ecf20Sopenharmony_ci				   u16 scid, u16 dcid)
44098c2ecf20Sopenharmony_ci{
44108c2ecf20Sopenharmony_ci	struct l2cap_cmd_rej_cid rej;
44118c2ecf20Sopenharmony_ci
44128c2ecf20Sopenharmony_ci	rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
44138c2ecf20Sopenharmony_ci	rej.scid = __cpu_to_le16(scid);
44148c2ecf20Sopenharmony_ci	rej.dcid = __cpu_to_le16(dcid);
44158c2ecf20Sopenharmony_ci
44168c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
44178c2ecf20Sopenharmony_ci}
44188c2ecf20Sopenharmony_ci
44198c2ecf20Sopenharmony_cistatic inline int l2cap_config_req(struct l2cap_conn *conn,
44208c2ecf20Sopenharmony_ci				   struct l2cap_cmd_hdr *cmd, u16 cmd_len,
44218c2ecf20Sopenharmony_ci				   u8 *data)
44228c2ecf20Sopenharmony_ci{
44238c2ecf20Sopenharmony_ci	struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
44248c2ecf20Sopenharmony_ci	u16 dcid, flags;
44258c2ecf20Sopenharmony_ci	u8 rsp[64];
44268c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
44278c2ecf20Sopenharmony_ci	int len, err = 0;
44288c2ecf20Sopenharmony_ci
44298c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*req))
44308c2ecf20Sopenharmony_ci		return -EPROTO;
44318c2ecf20Sopenharmony_ci
44328c2ecf20Sopenharmony_ci	dcid  = __le16_to_cpu(req->dcid);
44338c2ecf20Sopenharmony_ci	flags = __le16_to_cpu(req->flags);
44348c2ecf20Sopenharmony_ci
44358c2ecf20Sopenharmony_ci	BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
44368c2ecf20Sopenharmony_ci
44378c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_scid(conn, dcid);
44388c2ecf20Sopenharmony_ci	if (!chan) {
44398c2ecf20Sopenharmony_ci		cmd_reject_invalid_cid(conn, cmd->ident, dcid, 0);
44408c2ecf20Sopenharmony_ci		return 0;
44418c2ecf20Sopenharmony_ci	}
44428c2ecf20Sopenharmony_ci
44438c2ecf20Sopenharmony_ci	if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2 &&
44448c2ecf20Sopenharmony_ci	    chan->state != BT_CONNECTED) {
44458c2ecf20Sopenharmony_ci		cmd_reject_invalid_cid(conn, cmd->ident, chan->scid,
44468c2ecf20Sopenharmony_ci				       chan->dcid);
44478c2ecf20Sopenharmony_ci		goto unlock;
44488c2ecf20Sopenharmony_ci	}
44498c2ecf20Sopenharmony_ci
44508c2ecf20Sopenharmony_ci	/* Reject if config buffer is too small. */
44518c2ecf20Sopenharmony_ci	len = cmd_len - sizeof(*req);
44528c2ecf20Sopenharmony_ci	if (chan->conf_len + len > sizeof(chan->conf_req)) {
44538c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
44548c2ecf20Sopenharmony_ci			       l2cap_build_conf_rsp(chan, rsp,
44558c2ecf20Sopenharmony_ci			       L2CAP_CONF_REJECT, flags), rsp);
44568c2ecf20Sopenharmony_ci		goto unlock;
44578c2ecf20Sopenharmony_ci	}
44588c2ecf20Sopenharmony_ci
44598c2ecf20Sopenharmony_ci	/* Store config. */
44608c2ecf20Sopenharmony_ci	memcpy(chan->conf_req + chan->conf_len, req->data, len);
44618c2ecf20Sopenharmony_ci	chan->conf_len += len;
44628c2ecf20Sopenharmony_ci
44638c2ecf20Sopenharmony_ci	if (flags & L2CAP_CONF_FLAG_CONTINUATION) {
44648c2ecf20Sopenharmony_ci		/* Incomplete config. Send empty response. */
44658c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
44668c2ecf20Sopenharmony_ci			       l2cap_build_conf_rsp(chan, rsp,
44678c2ecf20Sopenharmony_ci			       L2CAP_CONF_SUCCESS, flags), rsp);
44688c2ecf20Sopenharmony_ci		goto unlock;
44698c2ecf20Sopenharmony_ci	}
44708c2ecf20Sopenharmony_ci
44718c2ecf20Sopenharmony_ci	/* Complete config. */
44728c2ecf20Sopenharmony_ci	len = l2cap_parse_conf_req(chan, rsp, sizeof(rsp));
44738c2ecf20Sopenharmony_ci	if (len < 0) {
44748c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
44758c2ecf20Sopenharmony_ci		goto unlock;
44768c2ecf20Sopenharmony_ci	}
44778c2ecf20Sopenharmony_ci
44788c2ecf20Sopenharmony_ci	chan->ident = cmd->ident;
44798c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
44808c2ecf20Sopenharmony_ci	if (chan->num_conf_rsp < L2CAP_CONF_MAX_CONF_RSP)
44818c2ecf20Sopenharmony_ci		chan->num_conf_rsp++;
44828c2ecf20Sopenharmony_ci
44838c2ecf20Sopenharmony_ci	/* Reset config buffer. */
44848c2ecf20Sopenharmony_ci	chan->conf_len = 0;
44858c2ecf20Sopenharmony_ci
44868c2ecf20Sopenharmony_ci	if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
44878c2ecf20Sopenharmony_ci		goto unlock;
44888c2ecf20Sopenharmony_ci
44898c2ecf20Sopenharmony_ci	if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
44908c2ecf20Sopenharmony_ci		set_default_fcs(chan);
44918c2ecf20Sopenharmony_ci
44928c2ecf20Sopenharmony_ci		if (chan->mode == L2CAP_MODE_ERTM ||
44938c2ecf20Sopenharmony_ci		    chan->mode == L2CAP_MODE_STREAMING)
44948c2ecf20Sopenharmony_ci			err = l2cap_ertm_init(chan);
44958c2ecf20Sopenharmony_ci
44968c2ecf20Sopenharmony_ci		if (err < 0)
44978c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, -err);
44988c2ecf20Sopenharmony_ci		else
44998c2ecf20Sopenharmony_ci			l2cap_chan_ready(chan);
45008c2ecf20Sopenharmony_ci
45018c2ecf20Sopenharmony_ci		goto unlock;
45028c2ecf20Sopenharmony_ci	}
45038c2ecf20Sopenharmony_ci
45048c2ecf20Sopenharmony_ci	if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
45058c2ecf20Sopenharmony_ci		u8 buf[64];
45068c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
45078c2ecf20Sopenharmony_ci			       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
45088c2ecf20Sopenharmony_ci		chan->num_conf_req++;
45098c2ecf20Sopenharmony_ci	}
45108c2ecf20Sopenharmony_ci
45118c2ecf20Sopenharmony_ci	/* Got Conf Rsp PENDING from remote side and assume we sent
45128c2ecf20Sopenharmony_ci	   Conf Rsp PENDING in the code above */
45138c2ecf20Sopenharmony_ci	if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
45148c2ecf20Sopenharmony_ci	    test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
45158c2ecf20Sopenharmony_ci
45168c2ecf20Sopenharmony_ci		/* check compatibility */
45178c2ecf20Sopenharmony_ci
45188c2ecf20Sopenharmony_ci		/* Send rsp for BR/EDR channel */
45198c2ecf20Sopenharmony_ci		if (!chan->hs_hcon)
45208c2ecf20Sopenharmony_ci			l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags);
45218c2ecf20Sopenharmony_ci		else
45228c2ecf20Sopenharmony_ci			chan->ident = cmd->ident;
45238c2ecf20Sopenharmony_ci	}
45248c2ecf20Sopenharmony_ci
45258c2ecf20Sopenharmony_ciunlock:
45268c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
45278c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
45288c2ecf20Sopenharmony_ci	return err;
45298c2ecf20Sopenharmony_ci}
45308c2ecf20Sopenharmony_ci
45318c2ecf20Sopenharmony_cistatic inline int l2cap_config_rsp(struct l2cap_conn *conn,
45328c2ecf20Sopenharmony_ci				   struct l2cap_cmd_hdr *cmd, u16 cmd_len,
45338c2ecf20Sopenharmony_ci				   u8 *data)
45348c2ecf20Sopenharmony_ci{
45358c2ecf20Sopenharmony_ci	struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
45368c2ecf20Sopenharmony_ci	u16 scid, flags, result;
45378c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
45388c2ecf20Sopenharmony_ci	int len = cmd_len - sizeof(*rsp);
45398c2ecf20Sopenharmony_ci	int err = 0;
45408c2ecf20Sopenharmony_ci
45418c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*rsp))
45428c2ecf20Sopenharmony_ci		return -EPROTO;
45438c2ecf20Sopenharmony_ci
45448c2ecf20Sopenharmony_ci	scid   = __le16_to_cpu(rsp->scid);
45458c2ecf20Sopenharmony_ci	flags  = __le16_to_cpu(rsp->flags);
45468c2ecf20Sopenharmony_ci	result = __le16_to_cpu(rsp->result);
45478c2ecf20Sopenharmony_ci
45488c2ecf20Sopenharmony_ci	BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x len %d", scid, flags,
45498c2ecf20Sopenharmony_ci	       result, len);
45508c2ecf20Sopenharmony_ci
45518c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_scid(conn, scid);
45528c2ecf20Sopenharmony_ci	if (!chan)
45538c2ecf20Sopenharmony_ci		return 0;
45548c2ecf20Sopenharmony_ci
45558c2ecf20Sopenharmony_ci	switch (result) {
45568c2ecf20Sopenharmony_ci	case L2CAP_CONF_SUCCESS:
45578c2ecf20Sopenharmony_ci		l2cap_conf_rfc_get(chan, rsp->data, len);
45588c2ecf20Sopenharmony_ci		clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
45598c2ecf20Sopenharmony_ci		break;
45608c2ecf20Sopenharmony_ci
45618c2ecf20Sopenharmony_ci	case L2CAP_CONF_PENDING:
45628c2ecf20Sopenharmony_ci		set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
45638c2ecf20Sopenharmony_ci
45648c2ecf20Sopenharmony_ci		if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
45658c2ecf20Sopenharmony_ci			char buf[64];
45668c2ecf20Sopenharmony_ci
45678c2ecf20Sopenharmony_ci			len = l2cap_parse_conf_rsp(chan, rsp->data, len,
45688c2ecf20Sopenharmony_ci						   buf, sizeof(buf), &result);
45698c2ecf20Sopenharmony_ci			if (len < 0) {
45708c2ecf20Sopenharmony_ci				l2cap_send_disconn_req(chan, ECONNRESET);
45718c2ecf20Sopenharmony_ci				goto done;
45728c2ecf20Sopenharmony_ci			}
45738c2ecf20Sopenharmony_ci
45748c2ecf20Sopenharmony_ci			if (!chan->hs_hcon) {
45758c2ecf20Sopenharmony_ci				l2cap_send_efs_conf_rsp(chan, buf, cmd->ident,
45768c2ecf20Sopenharmony_ci							0);
45778c2ecf20Sopenharmony_ci			} else {
45788c2ecf20Sopenharmony_ci				if (l2cap_check_efs(chan)) {
45798c2ecf20Sopenharmony_ci					amp_create_logical_link(chan);
45808c2ecf20Sopenharmony_ci					chan->ident = cmd->ident;
45818c2ecf20Sopenharmony_ci				}
45828c2ecf20Sopenharmony_ci			}
45838c2ecf20Sopenharmony_ci		}
45848c2ecf20Sopenharmony_ci		goto done;
45858c2ecf20Sopenharmony_ci
45868c2ecf20Sopenharmony_ci	case L2CAP_CONF_UNACCEPT:
45878c2ecf20Sopenharmony_ci		if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
45888c2ecf20Sopenharmony_ci			char req[64];
45898c2ecf20Sopenharmony_ci
45908c2ecf20Sopenharmony_ci			if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
45918c2ecf20Sopenharmony_ci				l2cap_send_disconn_req(chan, ECONNRESET);
45928c2ecf20Sopenharmony_ci				goto done;
45938c2ecf20Sopenharmony_ci			}
45948c2ecf20Sopenharmony_ci
45958c2ecf20Sopenharmony_ci			/* throw out any old stored conf requests */
45968c2ecf20Sopenharmony_ci			result = L2CAP_CONF_SUCCESS;
45978c2ecf20Sopenharmony_ci			len = l2cap_parse_conf_rsp(chan, rsp->data, len,
45988c2ecf20Sopenharmony_ci						   req, sizeof(req), &result);
45998c2ecf20Sopenharmony_ci			if (len < 0) {
46008c2ecf20Sopenharmony_ci				l2cap_send_disconn_req(chan, ECONNRESET);
46018c2ecf20Sopenharmony_ci				goto done;
46028c2ecf20Sopenharmony_ci			}
46038c2ecf20Sopenharmony_ci
46048c2ecf20Sopenharmony_ci			l2cap_send_cmd(conn, l2cap_get_ident(conn),
46058c2ecf20Sopenharmony_ci				       L2CAP_CONF_REQ, len, req);
46068c2ecf20Sopenharmony_ci			chan->num_conf_req++;
46078c2ecf20Sopenharmony_ci			if (result != L2CAP_CONF_SUCCESS)
46088c2ecf20Sopenharmony_ci				goto done;
46098c2ecf20Sopenharmony_ci			break;
46108c2ecf20Sopenharmony_ci		}
46118c2ecf20Sopenharmony_ci		fallthrough;
46128c2ecf20Sopenharmony_ci
46138c2ecf20Sopenharmony_ci	default:
46148c2ecf20Sopenharmony_ci		l2cap_chan_set_err(chan, ECONNRESET);
46158c2ecf20Sopenharmony_ci
46168c2ecf20Sopenharmony_ci		__set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
46178c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
46188c2ecf20Sopenharmony_ci		goto done;
46198c2ecf20Sopenharmony_ci	}
46208c2ecf20Sopenharmony_ci
46218c2ecf20Sopenharmony_ci	if (flags & L2CAP_CONF_FLAG_CONTINUATION)
46228c2ecf20Sopenharmony_ci		goto done;
46238c2ecf20Sopenharmony_ci
46248c2ecf20Sopenharmony_ci	set_bit(CONF_INPUT_DONE, &chan->conf_state);
46258c2ecf20Sopenharmony_ci
46268c2ecf20Sopenharmony_ci	if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
46278c2ecf20Sopenharmony_ci		set_default_fcs(chan);
46288c2ecf20Sopenharmony_ci
46298c2ecf20Sopenharmony_ci		if (chan->mode == L2CAP_MODE_ERTM ||
46308c2ecf20Sopenharmony_ci		    chan->mode == L2CAP_MODE_STREAMING)
46318c2ecf20Sopenharmony_ci			err = l2cap_ertm_init(chan);
46328c2ecf20Sopenharmony_ci
46338c2ecf20Sopenharmony_ci		if (err < 0)
46348c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, -err);
46358c2ecf20Sopenharmony_ci		else
46368c2ecf20Sopenharmony_ci			l2cap_chan_ready(chan);
46378c2ecf20Sopenharmony_ci	}
46388c2ecf20Sopenharmony_ci
46398c2ecf20Sopenharmony_cidone:
46408c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
46418c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
46428c2ecf20Sopenharmony_ci	return err;
46438c2ecf20Sopenharmony_ci}
46448c2ecf20Sopenharmony_ci
46458c2ecf20Sopenharmony_cistatic inline int l2cap_disconnect_req(struct l2cap_conn *conn,
46468c2ecf20Sopenharmony_ci				       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
46478c2ecf20Sopenharmony_ci				       u8 *data)
46488c2ecf20Sopenharmony_ci{
46498c2ecf20Sopenharmony_ci	struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
46508c2ecf20Sopenharmony_ci	struct l2cap_disconn_rsp rsp;
46518c2ecf20Sopenharmony_ci	u16 dcid, scid;
46528c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
46538c2ecf20Sopenharmony_ci
46548c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(*req))
46558c2ecf20Sopenharmony_ci		return -EPROTO;
46568c2ecf20Sopenharmony_ci
46578c2ecf20Sopenharmony_ci	scid = __le16_to_cpu(req->scid);
46588c2ecf20Sopenharmony_ci	dcid = __le16_to_cpu(req->dcid);
46598c2ecf20Sopenharmony_ci
46608c2ecf20Sopenharmony_ci	BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
46618c2ecf20Sopenharmony_ci
46628c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_scid(conn, dcid);
46638c2ecf20Sopenharmony_ci	if (!chan) {
46648c2ecf20Sopenharmony_ci		cmd_reject_invalid_cid(conn, cmd->ident, dcid, scid);
46658c2ecf20Sopenharmony_ci		return 0;
46668c2ecf20Sopenharmony_ci	}
46678c2ecf20Sopenharmony_ci
46688c2ecf20Sopenharmony_ci	rsp.dcid = cpu_to_le16(chan->scid);
46698c2ecf20Sopenharmony_ci	rsp.scid = cpu_to_le16(chan->dcid);
46708c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
46718c2ecf20Sopenharmony_ci
46728c2ecf20Sopenharmony_ci	chan->ops->set_shutdown(chan);
46738c2ecf20Sopenharmony_ci
46748c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
46758c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
46768c2ecf20Sopenharmony_ci	l2cap_chan_lock(chan);
46778c2ecf20Sopenharmony_ci	l2cap_chan_del(chan, ECONNRESET);
46788c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
46798c2ecf20Sopenharmony_ci
46808c2ecf20Sopenharmony_ci	chan->ops->close(chan);
46818c2ecf20Sopenharmony_ci
46828c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
46838c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
46848c2ecf20Sopenharmony_ci
46858c2ecf20Sopenharmony_ci	return 0;
46868c2ecf20Sopenharmony_ci}
46878c2ecf20Sopenharmony_ci
46888c2ecf20Sopenharmony_cistatic inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
46898c2ecf20Sopenharmony_ci				       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
46908c2ecf20Sopenharmony_ci				       u8 *data)
46918c2ecf20Sopenharmony_ci{
46928c2ecf20Sopenharmony_ci	struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
46938c2ecf20Sopenharmony_ci	u16 dcid, scid;
46948c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
46958c2ecf20Sopenharmony_ci
46968c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(*rsp))
46978c2ecf20Sopenharmony_ci		return -EPROTO;
46988c2ecf20Sopenharmony_ci
46998c2ecf20Sopenharmony_ci	scid = __le16_to_cpu(rsp->scid);
47008c2ecf20Sopenharmony_ci	dcid = __le16_to_cpu(rsp->dcid);
47018c2ecf20Sopenharmony_ci
47028c2ecf20Sopenharmony_ci	BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
47038c2ecf20Sopenharmony_ci
47048c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_scid(conn, scid);
47058c2ecf20Sopenharmony_ci	if (!chan) {
47068c2ecf20Sopenharmony_ci		return 0;
47078c2ecf20Sopenharmony_ci	}
47088c2ecf20Sopenharmony_ci
47098c2ecf20Sopenharmony_ci	if (chan->state != BT_DISCONN) {
47108c2ecf20Sopenharmony_ci		l2cap_chan_unlock(chan);
47118c2ecf20Sopenharmony_ci		l2cap_chan_put(chan);
47128c2ecf20Sopenharmony_ci		return 0;
47138c2ecf20Sopenharmony_ci	}
47148c2ecf20Sopenharmony_ci
47158c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
47168c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
47178c2ecf20Sopenharmony_ci	l2cap_chan_lock(chan);
47188c2ecf20Sopenharmony_ci	l2cap_chan_del(chan, 0);
47198c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
47208c2ecf20Sopenharmony_ci
47218c2ecf20Sopenharmony_ci	chan->ops->close(chan);
47228c2ecf20Sopenharmony_ci
47238c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
47248c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
47258c2ecf20Sopenharmony_ci
47268c2ecf20Sopenharmony_ci	return 0;
47278c2ecf20Sopenharmony_ci}
47288c2ecf20Sopenharmony_ci
47298c2ecf20Sopenharmony_cistatic inline int l2cap_information_req(struct l2cap_conn *conn,
47308c2ecf20Sopenharmony_ci					struct l2cap_cmd_hdr *cmd, u16 cmd_len,
47318c2ecf20Sopenharmony_ci					u8 *data)
47328c2ecf20Sopenharmony_ci{
47338c2ecf20Sopenharmony_ci	struct l2cap_info_req *req = (struct l2cap_info_req *) data;
47348c2ecf20Sopenharmony_ci	u16 type;
47358c2ecf20Sopenharmony_ci
47368c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(*req))
47378c2ecf20Sopenharmony_ci		return -EPROTO;
47388c2ecf20Sopenharmony_ci
47398c2ecf20Sopenharmony_ci	type = __le16_to_cpu(req->type);
47408c2ecf20Sopenharmony_ci
47418c2ecf20Sopenharmony_ci	BT_DBG("type 0x%4.4x", type);
47428c2ecf20Sopenharmony_ci
47438c2ecf20Sopenharmony_ci	if (type == L2CAP_IT_FEAT_MASK) {
47448c2ecf20Sopenharmony_ci		u8 buf[8];
47458c2ecf20Sopenharmony_ci		u32 feat_mask = l2cap_feat_mask;
47468c2ecf20Sopenharmony_ci		struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
47478c2ecf20Sopenharmony_ci		rsp->type   = cpu_to_le16(L2CAP_IT_FEAT_MASK);
47488c2ecf20Sopenharmony_ci		rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
47498c2ecf20Sopenharmony_ci		if (!disable_ertm)
47508c2ecf20Sopenharmony_ci			feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
47518c2ecf20Sopenharmony_ci				| L2CAP_FEAT_FCS;
47528c2ecf20Sopenharmony_ci		if (conn->local_fixed_chan & L2CAP_FC_A2MP)
47538c2ecf20Sopenharmony_ci			feat_mask |= L2CAP_FEAT_EXT_FLOW
47548c2ecf20Sopenharmony_ci				| L2CAP_FEAT_EXT_WINDOW;
47558c2ecf20Sopenharmony_ci
47568c2ecf20Sopenharmony_ci		put_unaligned_le32(feat_mask, rsp->data);
47578c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf),
47588c2ecf20Sopenharmony_ci			       buf);
47598c2ecf20Sopenharmony_ci	} else if (type == L2CAP_IT_FIXED_CHAN) {
47608c2ecf20Sopenharmony_ci		u8 buf[12];
47618c2ecf20Sopenharmony_ci		struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
47628c2ecf20Sopenharmony_ci
47638c2ecf20Sopenharmony_ci		rsp->type   = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
47648c2ecf20Sopenharmony_ci		rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
47658c2ecf20Sopenharmony_ci		rsp->data[0] = conn->local_fixed_chan;
47668c2ecf20Sopenharmony_ci		memset(rsp->data + 1, 0, 7);
47678c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf),
47688c2ecf20Sopenharmony_ci			       buf);
47698c2ecf20Sopenharmony_ci	} else {
47708c2ecf20Sopenharmony_ci		struct l2cap_info_rsp rsp;
47718c2ecf20Sopenharmony_ci		rsp.type   = cpu_to_le16(type);
47728c2ecf20Sopenharmony_ci		rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
47738c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp),
47748c2ecf20Sopenharmony_ci			       &rsp);
47758c2ecf20Sopenharmony_ci	}
47768c2ecf20Sopenharmony_ci
47778c2ecf20Sopenharmony_ci	return 0;
47788c2ecf20Sopenharmony_ci}
47798c2ecf20Sopenharmony_ci
47808c2ecf20Sopenharmony_cistatic inline int l2cap_information_rsp(struct l2cap_conn *conn,
47818c2ecf20Sopenharmony_ci					struct l2cap_cmd_hdr *cmd, u16 cmd_len,
47828c2ecf20Sopenharmony_ci					u8 *data)
47838c2ecf20Sopenharmony_ci{
47848c2ecf20Sopenharmony_ci	struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
47858c2ecf20Sopenharmony_ci	u16 type, result;
47868c2ecf20Sopenharmony_ci
47878c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*rsp))
47888c2ecf20Sopenharmony_ci		return -EPROTO;
47898c2ecf20Sopenharmony_ci
47908c2ecf20Sopenharmony_ci	type   = __le16_to_cpu(rsp->type);
47918c2ecf20Sopenharmony_ci	result = __le16_to_cpu(rsp->result);
47928c2ecf20Sopenharmony_ci
47938c2ecf20Sopenharmony_ci	BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
47948c2ecf20Sopenharmony_ci
47958c2ecf20Sopenharmony_ci	/* L2CAP Info req/rsp are unbound to channels, add extra checks */
47968c2ecf20Sopenharmony_ci	if (cmd->ident != conn->info_ident ||
47978c2ecf20Sopenharmony_ci	    conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
47988c2ecf20Sopenharmony_ci		return 0;
47998c2ecf20Sopenharmony_ci
48008c2ecf20Sopenharmony_ci	cancel_delayed_work(&conn->info_timer);
48018c2ecf20Sopenharmony_ci
48028c2ecf20Sopenharmony_ci	if (result != L2CAP_IR_SUCCESS) {
48038c2ecf20Sopenharmony_ci		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
48048c2ecf20Sopenharmony_ci		conn->info_ident = 0;
48058c2ecf20Sopenharmony_ci
48068c2ecf20Sopenharmony_ci		l2cap_conn_start(conn);
48078c2ecf20Sopenharmony_ci
48088c2ecf20Sopenharmony_ci		return 0;
48098c2ecf20Sopenharmony_ci	}
48108c2ecf20Sopenharmony_ci
48118c2ecf20Sopenharmony_ci	switch (type) {
48128c2ecf20Sopenharmony_ci	case L2CAP_IT_FEAT_MASK:
48138c2ecf20Sopenharmony_ci		conn->feat_mask = get_unaligned_le32(rsp->data);
48148c2ecf20Sopenharmony_ci
48158c2ecf20Sopenharmony_ci		if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
48168c2ecf20Sopenharmony_ci			struct l2cap_info_req req;
48178c2ecf20Sopenharmony_ci			req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
48188c2ecf20Sopenharmony_ci
48198c2ecf20Sopenharmony_ci			conn->info_ident = l2cap_get_ident(conn);
48208c2ecf20Sopenharmony_ci
48218c2ecf20Sopenharmony_ci			l2cap_send_cmd(conn, conn->info_ident,
48228c2ecf20Sopenharmony_ci				       L2CAP_INFO_REQ, sizeof(req), &req);
48238c2ecf20Sopenharmony_ci		} else {
48248c2ecf20Sopenharmony_ci			conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
48258c2ecf20Sopenharmony_ci			conn->info_ident = 0;
48268c2ecf20Sopenharmony_ci
48278c2ecf20Sopenharmony_ci			l2cap_conn_start(conn);
48288c2ecf20Sopenharmony_ci		}
48298c2ecf20Sopenharmony_ci		break;
48308c2ecf20Sopenharmony_ci
48318c2ecf20Sopenharmony_ci	case L2CAP_IT_FIXED_CHAN:
48328c2ecf20Sopenharmony_ci		conn->remote_fixed_chan = rsp->data[0];
48338c2ecf20Sopenharmony_ci		conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
48348c2ecf20Sopenharmony_ci		conn->info_ident = 0;
48358c2ecf20Sopenharmony_ci
48368c2ecf20Sopenharmony_ci		l2cap_conn_start(conn);
48378c2ecf20Sopenharmony_ci		break;
48388c2ecf20Sopenharmony_ci	}
48398c2ecf20Sopenharmony_ci
48408c2ecf20Sopenharmony_ci	return 0;
48418c2ecf20Sopenharmony_ci}
48428c2ecf20Sopenharmony_ci
48438c2ecf20Sopenharmony_cistatic int l2cap_create_channel_req(struct l2cap_conn *conn,
48448c2ecf20Sopenharmony_ci				    struct l2cap_cmd_hdr *cmd,
48458c2ecf20Sopenharmony_ci				    u16 cmd_len, void *data)
48468c2ecf20Sopenharmony_ci{
48478c2ecf20Sopenharmony_ci	struct l2cap_create_chan_req *req = data;
48488c2ecf20Sopenharmony_ci	struct l2cap_create_chan_rsp rsp;
48498c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
48508c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
48518c2ecf20Sopenharmony_ci	u16 psm, scid;
48528c2ecf20Sopenharmony_ci
48538c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(*req))
48548c2ecf20Sopenharmony_ci		return -EPROTO;
48558c2ecf20Sopenharmony_ci
48568c2ecf20Sopenharmony_ci	if (!(conn->local_fixed_chan & L2CAP_FC_A2MP))
48578c2ecf20Sopenharmony_ci		return -EINVAL;
48588c2ecf20Sopenharmony_ci
48598c2ecf20Sopenharmony_ci	psm = le16_to_cpu(req->psm);
48608c2ecf20Sopenharmony_ci	scid = le16_to_cpu(req->scid);
48618c2ecf20Sopenharmony_ci
48628c2ecf20Sopenharmony_ci	BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id);
48638c2ecf20Sopenharmony_ci
48648c2ecf20Sopenharmony_ci	/* For controller id 0 make BR/EDR connection */
48658c2ecf20Sopenharmony_ci	if (req->amp_id == AMP_ID_BREDR) {
48668c2ecf20Sopenharmony_ci		l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP,
48678c2ecf20Sopenharmony_ci			      req->amp_id);
48688c2ecf20Sopenharmony_ci		return 0;
48698c2ecf20Sopenharmony_ci	}
48708c2ecf20Sopenharmony_ci
48718c2ecf20Sopenharmony_ci	/* Validate AMP controller id */
48728c2ecf20Sopenharmony_ci	hdev = hci_dev_get(req->amp_id);
48738c2ecf20Sopenharmony_ci	if (!hdev)
48748c2ecf20Sopenharmony_ci		goto error;
48758c2ecf20Sopenharmony_ci
48768c2ecf20Sopenharmony_ci	if (hdev->dev_type != HCI_AMP || !test_bit(HCI_UP, &hdev->flags)) {
48778c2ecf20Sopenharmony_ci		hci_dev_put(hdev);
48788c2ecf20Sopenharmony_ci		goto error;
48798c2ecf20Sopenharmony_ci	}
48808c2ecf20Sopenharmony_ci
48818c2ecf20Sopenharmony_ci	chan = l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP,
48828c2ecf20Sopenharmony_ci			     req->amp_id);
48838c2ecf20Sopenharmony_ci	if (chan) {
48848c2ecf20Sopenharmony_ci		struct amp_mgr *mgr = conn->hcon->amp_mgr;
48858c2ecf20Sopenharmony_ci		struct hci_conn *hs_hcon;
48868c2ecf20Sopenharmony_ci
48878c2ecf20Sopenharmony_ci		hs_hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK,
48888c2ecf20Sopenharmony_ci						  &conn->hcon->dst);
48898c2ecf20Sopenharmony_ci		if (!hs_hcon) {
48908c2ecf20Sopenharmony_ci			hci_dev_put(hdev);
48918c2ecf20Sopenharmony_ci			cmd_reject_invalid_cid(conn, cmd->ident, chan->scid,
48928c2ecf20Sopenharmony_ci					       chan->dcid);
48938c2ecf20Sopenharmony_ci			return 0;
48948c2ecf20Sopenharmony_ci		}
48958c2ecf20Sopenharmony_ci
48968c2ecf20Sopenharmony_ci		BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon);
48978c2ecf20Sopenharmony_ci
48988c2ecf20Sopenharmony_ci		mgr->bredr_chan = chan;
48998c2ecf20Sopenharmony_ci		chan->hs_hcon = hs_hcon;
49008c2ecf20Sopenharmony_ci		chan->fcs = L2CAP_FCS_NONE;
49018c2ecf20Sopenharmony_ci		conn->mtu = hdev->block_mtu;
49028c2ecf20Sopenharmony_ci	}
49038c2ecf20Sopenharmony_ci
49048c2ecf20Sopenharmony_ci	hci_dev_put(hdev);
49058c2ecf20Sopenharmony_ci
49068c2ecf20Sopenharmony_ci	return 0;
49078c2ecf20Sopenharmony_ci
49088c2ecf20Sopenharmony_cierror:
49098c2ecf20Sopenharmony_ci	rsp.dcid = 0;
49108c2ecf20Sopenharmony_ci	rsp.scid = cpu_to_le16(scid);
49118c2ecf20Sopenharmony_ci	rsp.result = cpu_to_le16(L2CAP_CR_BAD_AMP);
49128c2ecf20Sopenharmony_ci	rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
49138c2ecf20Sopenharmony_ci
49148c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
49158c2ecf20Sopenharmony_ci		       sizeof(rsp), &rsp);
49168c2ecf20Sopenharmony_ci
49178c2ecf20Sopenharmony_ci	return 0;
49188c2ecf20Sopenharmony_ci}
49198c2ecf20Sopenharmony_ci
49208c2ecf20Sopenharmony_cistatic void l2cap_send_move_chan_req(struct l2cap_chan *chan, u8 dest_amp_id)
49218c2ecf20Sopenharmony_ci{
49228c2ecf20Sopenharmony_ci	struct l2cap_move_chan_req req;
49238c2ecf20Sopenharmony_ci	u8 ident;
49248c2ecf20Sopenharmony_ci
49258c2ecf20Sopenharmony_ci	BT_DBG("chan %p, dest_amp_id %d", chan, dest_amp_id);
49268c2ecf20Sopenharmony_ci
49278c2ecf20Sopenharmony_ci	ident = l2cap_get_ident(chan->conn);
49288c2ecf20Sopenharmony_ci	chan->ident = ident;
49298c2ecf20Sopenharmony_ci
49308c2ecf20Sopenharmony_ci	req.icid = cpu_to_le16(chan->scid);
49318c2ecf20Sopenharmony_ci	req.dest_amp_id = dest_amp_id;
49328c2ecf20Sopenharmony_ci
49338c2ecf20Sopenharmony_ci	l2cap_send_cmd(chan->conn, ident, L2CAP_MOVE_CHAN_REQ, sizeof(req),
49348c2ecf20Sopenharmony_ci		       &req);
49358c2ecf20Sopenharmony_ci
49368c2ecf20Sopenharmony_ci	__set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
49378c2ecf20Sopenharmony_ci}
49388c2ecf20Sopenharmony_ci
49398c2ecf20Sopenharmony_cistatic void l2cap_send_move_chan_rsp(struct l2cap_chan *chan, u16 result)
49408c2ecf20Sopenharmony_ci{
49418c2ecf20Sopenharmony_ci	struct l2cap_move_chan_rsp rsp;
49428c2ecf20Sopenharmony_ci
49438c2ecf20Sopenharmony_ci	BT_DBG("chan %p, result 0x%4.4x", chan, result);
49448c2ecf20Sopenharmony_ci
49458c2ecf20Sopenharmony_ci	rsp.icid = cpu_to_le16(chan->dcid);
49468c2ecf20Sopenharmony_ci	rsp.result = cpu_to_le16(result);
49478c2ecf20Sopenharmony_ci
49488c2ecf20Sopenharmony_ci	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_RSP,
49498c2ecf20Sopenharmony_ci		       sizeof(rsp), &rsp);
49508c2ecf20Sopenharmony_ci}
49518c2ecf20Sopenharmony_ci
49528c2ecf20Sopenharmony_cistatic void l2cap_send_move_chan_cfm(struct l2cap_chan *chan, u16 result)
49538c2ecf20Sopenharmony_ci{
49548c2ecf20Sopenharmony_ci	struct l2cap_move_chan_cfm cfm;
49558c2ecf20Sopenharmony_ci
49568c2ecf20Sopenharmony_ci	BT_DBG("chan %p, result 0x%4.4x", chan, result);
49578c2ecf20Sopenharmony_ci
49588c2ecf20Sopenharmony_ci	chan->ident = l2cap_get_ident(chan->conn);
49598c2ecf20Sopenharmony_ci
49608c2ecf20Sopenharmony_ci	cfm.icid = cpu_to_le16(chan->scid);
49618c2ecf20Sopenharmony_ci	cfm.result = cpu_to_le16(result);
49628c2ecf20Sopenharmony_ci
49638c2ecf20Sopenharmony_ci	l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_CFM,
49648c2ecf20Sopenharmony_ci		       sizeof(cfm), &cfm);
49658c2ecf20Sopenharmony_ci
49668c2ecf20Sopenharmony_ci	__set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
49678c2ecf20Sopenharmony_ci}
49688c2ecf20Sopenharmony_ci
49698c2ecf20Sopenharmony_cistatic void l2cap_send_move_chan_cfm_icid(struct l2cap_conn *conn, u16 icid)
49708c2ecf20Sopenharmony_ci{
49718c2ecf20Sopenharmony_ci	struct l2cap_move_chan_cfm cfm;
49728c2ecf20Sopenharmony_ci
49738c2ecf20Sopenharmony_ci	BT_DBG("conn %p, icid 0x%4.4x", conn, icid);
49748c2ecf20Sopenharmony_ci
49758c2ecf20Sopenharmony_ci	cfm.icid = cpu_to_le16(icid);
49768c2ecf20Sopenharmony_ci	cfm.result = cpu_to_le16(L2CAP_MC_UNCONFIRMED);
49778c2ecf20Sopenharmony_ci
49788c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_MOVE_CHAN_CFM,
49798c2ecf20Sopenharmony_ci		       sizeof(cfm), &cfm);
49808c2ecf20Sopenharmony_ci}
49818c2ecf20Sopenharmony_ci
49828c2ecf20Sopenharmony_cistatic void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
49838c2ecf20Sopenharmony_ci					 u16 icid)
49848c2ecf20Sopenharmony_ci{
49858c2ecf20Sopenharmony_ci	struct l2cap_move_chan_cfm_rsp rsp;
49868c2ecf20Sopenharmony_ci
49878c2ecf20Sopenharmony_ci	BT_DBG("icid 0x%4.4x", icid);
49888c2ecf20Sopenharmony_ci
49898c2ecf20Sopenharmony_ci	rsp.icid = cpu_to_le16(icid);
49908c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
49918c2ecf20Sopenharmony_ci}
49928c2ecf20Sopenharmony_ci
49938c2ecf20Sopenharmony_cistatic void __release_logical_link(struct l2cap_chan *chan)
49948c2ecf20Sopenharmony_ci{
49958c2ecf20Sopenharmony_ci	chan->hs_hchan = NULL;
49968c2ecf20Sopenharmony_ci	chan->hs_hcon = NULL;
49978c2ecf20Sopenharmony_ci
49988c2ecf20Sopenharmony_ci	/* Placeholder - release the logical link */
49998c2ecf20Sopenharmony_ci}
50008c2ecf20Sopenharmony_ci
50018c2ecf20Sopenharmony_cistatic void l2cap_logical_fail(struct l2cap_chan *chan)
50028c2ecf20Sopenharmony_ci{
50038c2ecf20Sopenharmony_ci	/* Logical link setup failed */
50048c2ecf20Sopenharmony_ci	if (chan->state != BT_CONNECTED) {
50058c2ecf20Sopenharmony_ci		/* Create channel failure, disconnect */
50068c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
50078c2ecf20Sopenharmony_ci		return;
50088c2ecf20Sopenharmony_ci	}
50098c2ecf20Sopenharmony_ci
50108c2ecf20Sopenharmony_ci	switch (chan->move_role) {
50118c2ecf20Sopenharmony_ci	case L2CAP_MOVE_ROLE_RESPONDER:
50128c2ecf20Sopenharmony_ci		l2cap_move_done(chan);
50138c2ecf20Sopenharmony_ci		l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_SUPP);
50148c2ecf20Sopenharmony_ci		break;
50158c2ecf20Sopenharmony_ci	case L2CAP_MOVE_ROLE_INITIATOR:
50168c2ecf20Sopenharmony_ci		if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP ||
50178c2ecf20Sopenharmony_ci		    chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_CFM) {
50188c2ecf20Sopenharmony_ci			/* Remote has only sent pending or
50198c2ecf20Sopenharmony_ci			 * success responses, clean up
50208c2ecf20Sopenharmony_ci			 */
50218c2ecf20Sopenharmony_ci			l2cap_move_done(chan);
50228c2ecf20Sopenharmony_ci		}
50238c2ecf20Sopenharmony_ci
50248c2ecf20Sopenharmony_ci		/* Other amp move states imply that the move
50258c2ecf20Sopenharmony_ci		 * has already aborted
50268c2ecf20Sopenharmony_ci		 */
50278c2ecf20Sopenharmony_ci		l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
50288c2ecf20Sopenharmony_ci		break;
50298c2ecf20Sopenharmony_ci	}
50308c2ecf20Sopenharmony_ci}
50318c2ecf20Sopenharmony_ci
50328c2ecf20Sopenharmony_cistatic void l2cap_logical_finish_create(struct l2cap_chan *chan,
50338c2ecf20Sopenharmony_ci					struct hci_chan *hchan)
50348c2ecf20Sopenharmony_ci{
50358c2ecf20Sopenharmony_ci	struct l2cap_conf_rsp rsp;
50368c2ecf20Sopenharmony_ci
50378c2ecf20Sopenharmony_ci	chan->hs_hchan = hchan;
50388c2ecf20Sopenharmony_ci	chan->hs_hcon->l2cap_data = chan->conn;
50398c2ecf20Sopenharmony_ci
50408c2ecf20Sopenharmony_ci	l2cap_send_efs_conf_rsp(chan, &rsp, chan->ident, 0);
50418c2ecf20Sopenharmony_ci
50428c2ecf20Sopenharmony_ci	if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
50438c2ecf20Sopenharmony_ci		int err;
50448c2ecf20Sopenharmony_ci
50458c2ecf20Sopenharmony_ci		set_default_fcs(chan);
50468c2ecf20Sopenharmony_ci
50478c2ecf20Sopenharmony_ci		err = l2cap_ertm_init(chan);
50488c2ecf20Sopenharmony_ci		if (err < 0)
50498c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, -err);
50508c2ecf20Sopenharmony_ci		else
50518c2ecf20Sopenharmony_ci			l2cap_chan_ready(chan);
50528c2ecf20Sopenharmony_ci	}
50538c2ecf20Sopenharmony_ci}
50548c2ecf20Sopenharmony_ci
50558c2ecf20Sopenharmony_cistatic void l2cap_logical_finish_move(struct l2cap_chan *chan,
50568c2ecf20Sopenharmony_ci				      struct hci_chan *hchan)
50578c2ecf20Sopenharmony_ci{
50588c2ecf20Sopenharmony_ci	chan->hs_hcon = hchan->conn;
50598c2ecf20Sopenharmony_ci	chan->hs_hcon->l2cap_data = chan->conn;
50608c2ecf20Sopenharmony_ci
50618c2ecf20Sopenharmony_ci	BT_DBG("move_state %d", chan->move_state);
50628c2ecf20Sopenharmony_ci
50638c2ecf20Sopenharmony_ci	switch (chan->move_state) {
50648c2ecf20Sopenharmony_ci	case L2CAP_MOVE_WAIT_LOGICAL_COMP:
50658c2ecf20Sopenharmony_ci		/* Move confirm will be sent after a success
50668c2ecf20Sopenharmony_ci		 * response is received
50678c2ecf20Sopenharmony_ci		 */
50688c2ecf20Sopenharmony_ci		chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
50698c2ecf20Sopenharmony_ci		break;
50708c2ecf20Sopenharmony_ci	case L2CAP_MOVE_WAIT_LOGICAL_CFM:
50718c2ecf20Sopenharmony_ci		if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
50728c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
50738c2ecf20Sopenharmony_ci		} else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
50748c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP;
50758c2ecf20Sopenharmony_ci			l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED);
50768c2ecf20Sopenharmony_ci		} else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
50778c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
50788c2ecf20Sopenharmony_ci			l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS);
50798c2ecf20Sopenharmony_ci		}
50808c2ecf20Sopenharmony_ci		break;
50818c2ecf20Sopenharmony_ci	default:
50828c2ecf20Sopenharmony_ci		/* Move was not in expected state, free the channel */
50838c2ecf20Sopenharmony_ci		__release_logical_link(chan);
50848c2ecf20Sopenharmony_ci
50858c2ecf20Sopenharmony_ci		chan->move_state = L2CAP_MOVE_STABLE;
50868c2ecf20Sopenharmony_ci	}
50878c2ecf20Sopenharmony_ci}
50888c2ecf20Sopenharmony_ci
50898c2ecf20Sopenharmony_ci/* Call with chan locked */
50908c2ecf20Sopenharmony_civoid l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
50918c2ecf20Sopenharmony_ci		       u8 status)
50928c2ecf20Sopenharmony_ci{
50938c2ecf20Sopenharmony_ci	BT_DBG("chan %p, hchan %p, status %d", chan, hchan, status);
50948c2ecf20Sopenharmony_ci
50958c2ecf20Sopenharmony_ci	if (status) {
50968c2ecf20Sopenharmony_ci		l2cap_logical_fail(chan);
50978c2ecf20Sopenharmony_ci		__release_logical_link(chan);
50988c2ecf20Sopenharmony_ci		return;
50998c2ecf20Sopenharmony_ci	}
51008c2ecf20Sopenharmony_ci
51018c2ecf20Sopenharmony_ci	if (chan->state != BT_CONNECTED) {
51028c2ecf20Sopenharmony_ci		/* Ignore logical link if channel is on BR/EDR */
51038c2ecf20Sopenharmony_ci		if (chan->local_amp_id != AMP_ID_BREDR)
51048c2ecf20Sopenharmony_ci			l2cap_logical_finish_create(chan, hchan);
51058c2ecf20Sopenharmony_ci	} else {
51068c2ecf20Sopenharmony_ci		l2cap_logical_finish_move(chan, hchan);
51078c2ecf20Sopenharmony_ci	}
51088c2ecf20Sopenharmony_ci}
51098c2ecf20Sopenharmony_ci
51108c2ecf20Sopenharmony_civoid l2cap_move_start(struct l2cap_chan *chan)
51118c2ecf20Sopenharmony_ci{
51128c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
51138c2ecf20Sopenharmony_ci
51148c2ecf20Sopenharmony_ci	if (chan->local_amp_id == AMP_ID_BREDR) {
51158c2ecf20Sopenharmony_ci		if (chan->chan_policy != BT_CHANNEL_POLICY_AMP_PREFERRED)
51168c2ecf20Sopenharmony_ci			return;
51178c2ecf20Sopenharmony_ci		chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
51188c2ecf20Sopenharmony_ci		chan->move_state = L2CAP_MOVE_WAIT_PREPARE;
51198c2ecf20Sopenharmony_ci		/* Placeholder - start physical link setup */
51208c2ecf20Sopenharmony_ci	} else {
51218c2ecf20Sopenharmony_ci		chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
51228c2ecf20Sopenharmony_ci		chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
51238c2ecf20Sopenharmony_ci		chan->move_id = 0;
51248c2ecf20Sopenharmony_ci		l2cap_move_setup(chan);
51258c2ecf20Sopenharmony_ci		l2cap_send_move_chan_req(chan, 0);
51268c2ecf20Sopenharmony_ci	}
51278c2ecf20Sopenharmony_ci}
51288c2ecf20Sopenharmony_ci
51298c2ecf20Sopenharmony_cistatic void l2cap_do_create(struct l2cap_chan *chan, int result,
51308c2ecf20Sopenharmony_ci			    u8 local_amp_id, u8 remote_amp_id)
51318c2ecf20Sopenharmony_ci{
51328c2ecf20Sopenharmony_ci	BT_DBG("chan %p state %s %u -> %u", chan, state_to_string(chan->state),
51338c2ecf20Sopenharmony_ci	       local_amp_id, remote_amp_id);
51348c2ecf20Sopenharmony_ci
51358c2ecf20Sopenharmony_ci	chan->fcs = L2CAP_FCS_NONE;
51368c2ecf20Sopenharmony_ci
51378c2ecf20Sopenharmony_ci	/* Outgoing channel on AMP */
51388c2ecf20Sopenharmony_ci	if (chan->state == BT_CONNECT) {
51398c2ecf20Sopenharmony_ci		if (result == L2CAP_CR_SUCCESS) {
51408c2ecf20Sopenharmony_ci			chan->local_amp_id = local_amp_id;
51418c2ecf20Sopenharmony_ci			l2cap_send_create_chan_req(chan, remote_amp_id);
51428c2ecf20Sopenharmony_ci		} else {
51438c2ecf20Sopenharmony_ci			/* Revert to BR/EDR connect */
51448c2ecf20Sopenharmony_ci			l2cap_send_conn_req(chan);
51458c2ecf20Sopenharmony_ci		}
51468c2ecf20Sopenharmony_ci
51478c2ecf20Sopenharmony_ci		return;
51488c2ecf20Sopenharmony_ci	}
51498c2ecf20Sopenharmony_ci
51508c2ecf20Sopenharmony_ci	/* Incoming channel on AMP */
51518c2ecf20Sopenharmony_ci	if (__l2cap_no_conn_pending(chan)) {
51528c2ecf20Sopenharmony_ci		struct l2cap_conn_rsp rsp;
51538c2ecf20Sopenharmony_ci		char buf[128];
51548c2ecf20Sopenharmony_ci		rsp.scid = cpu_to_le16(chan->dcid);
51558c2ecf20Sopenharmony_ci		rsp.dcid = cpu_to_le16(chan->scid);
51568c2ecf20Sopenharmony_ci
51578c2ecf20Sopenharmony_ci		if (result == L2CAP_CR_SUCCESS) {
51588c2ecf20Sopenharmony_ci			/* Send successful response */
51598c2ecf20Sopenharmony_ci			rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
51608c2ecf20Sopenharmony_ci			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
51618c2ecf20Sopenharmony_ci		} else {
51628c2ecf20Sopenharmony_ci			/* Send negative response */
51638c2ecf20Sopenharmony_ci			rsp.result = cpu_to_le16(L2CAP_CR_NO_MEM);
51648c2ecf20Sopenharmony_ci			rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
51658c2ecf20Sopenharmony_ci		}
51668c2ecf20Sopenharmony_ci
51678c2ecf20Sopenharmony_ci		l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP,
51688c2ecf20Sopenharmony_ci			       sizeof(rsp), &rsp);
51698c2ecf20Sopenharmony_ci
51708c2ecf20Sopenharmony_ci		if (result == L2CAP_CR_SUCCESS) {
51718c2ecf20Sopenharmony_ci			l2cap_state_change(chan, BT_CONFIG);
51728c2ecf20Sopenharmony_ci			set_bit(CONF_REQ_SENT, &chan->conf_state);
51738c2ecf20Sopenharmony_ci			l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn),
51748c2ecf20Sopenharmony_ci				       L2CAP_CONF_REQ,
51758c2ecf20Sopenharmony_ci				       l2cap_build_conf_req(chan, buf, sizeof(buf)), buf);
51768c2ecf20Sopenharmony_ci			chan->num_conf_req++;
51778c2ecf20Sopenharmony_ci		}
51788c2ecf20Sopenharmony_ci	}
51798c2ecf20Sopenharmony_ci}
51808c2ecf20Sopenharmony_ci
51818c2ecf20Sopenharmony_cistatic void l2cap_do_move_initiate(struct l2cap_chan *chan, u8 local_amp_id,
51828c2ecf20Sopenharmony_ci				   u8 remote_amp_id)
51838c2ecf20Sopenharmony_ci{
51848c2ecf20Sopenharmony_ci	l2cap_move_setup(chan);
51858c2ecf20Sopenharmony_ci	chan->move_id = local_amp_id;
51868c2ecf20Sopenharmony_ci	chan->move_state = L2CAP_MOVE_WAIT_RSP;
51878c2ecf20Sopenharmony_ci
51888c2ecf20Sopenharmony_ci	l2cap_send_move_chan_req(chan, remote_amp_id);
51898c2ecf20Sopenharmony_ci}
51908c2ecf20Sopenharmony_ci
51918c2ecf20Sopenharmony_cistatic void l2cap_do_move_respond(struct l2cap_chan *chan, int result)
51928c2ecf20Sopenharmony_ci{
51938c2ecf20Sopenharmony_ci	struct hci_chan *hchan = NULL;
51948c2ecf20Sopenharmony_ci
51958c2ecf20Sopenharmony_ci	/* Placeholder - get hci_chan for logical link */
51968c2ecf20Sopenharmony_ci
51978c2ecf20Sopenharmony_ci	if (hchan) {
51988c2ecf20Sopenharmony_ci		if (hchan->state == BT_CONNECTED) {
51998c2ecf20Sopenharmony_ci			/* Logical link is ready to go */
52008c2ecf20Sopenharmony_ci			chan->hs_hcon = hchan->conn;
52018c2ecf20Sopenharmony_ci			chan->hs_hcon->l2cap_data = chan->conn;
52028c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
52038c2ecf20Sopenharmony_ci			l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS);
52048c2ecf20Sopenharmony_ci
52058c2ecf20Sopenharmony_ci			l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS);
52068c2ecf20Sopenharmony_ci		} else {
52078c2ecf20Sopenharmony_ci			/* Wait for logical link to be ready */
52088c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM;
52098c2ecf20Sopenharmony_ci		}
52108c2ecf20Sopenharmony_ci	} else {
52118c2ecf20Sopenharmony_ci		/* Logical link not available */
52128c2ecf20Sopenharmony_ci		l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_ALLOWED);
52138c2ecf20Sopenharmony_ci	}
52148c2ecf20Sopenharmony_ci}
52158c2ecf20Sopenharmony_ci
52168c2ecf20Sopenharmony_cistatic void l2cap_do_move_cancel(struct l2cap_chan *chan, int result)
52178c2ecf20Sopenharmony_ci{
52188c2ecf20Sopenharmony_ci	if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
52198c2ecf20Sopenharmony_ci		u8 rsp_result;
52208c2ecf20Sopenharmony_ci		if (result == -EINVAL)
52218c2ecf20Sopenharmony_ci			rsp_result = L2CAP_MR_BAD_ID;
52228c2ecf20Sopenharmony_ci		else
52238c2ecf20Sopenharmony_ci			rsp_result = L2CAP_MR_NOT_ALLOWED;
52248c2ecf20Sopenharmony_ci
52258c2ecf20Sopenharmony_ci		l2cap_send_move_chan_rsp(chan, rsp_result);
52268c2ecf20Sopenharmony_ci	}
52278c2ecf20Sopenharmony_ci
52288c2ecf20Sopenharmony_ci	chan->move_role = L2CAP_MOVE_ROLE_NONE;
52298c2ecf20Sopenharmony_ci	chan->move_state = L2CAP_MOVE_STABLE;
52308c2ecf20Sopenharmony_ci
52318c2ecf20Sopenharmony_ci	/* Restart data transmission */
52328c2ecf20Sopenharmony_ci	l2cap_ertm_send(chan);
52338c2ecf20Sopenharmony_ci}
52348c2ecf20Sopenharmony_ci
52358c2ecf20Sopenharmony_ci/* Invoke with locked chan */
52368c2ecf20Sopenharmony_civoid __l2cap_physical_cfm(struct l2cap_chan *chan, int result)
52378c2ecf20Sopenharmony_ci{
52388c2ecf20Sopenharmony_ci	u8 local_amp_id = chan->local_amp_id;
52398c2ecf20Sopenharmony_ci	u8 remote_amp_id = chan->remote_amp_id;
52408c2ecf20Sopenharmony_ci
52418c2ecf20Sopenharmony_ci	BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d",
52428c2ecf20Sopenharmony_ci	       chan, result, local_amp_id, remote_amp_id);
52438c2ecf20Sopenharmony_ci
52448c2ecf20Sopenharmony_ci	if (chan->state == BT_DISCONN || chan->state == BT_CLOSED)
52458c2ecf20Sopenharmony_ci		return;
52468c2ecf20Sopenharmony_ci
52478c2ecf20Sopenharmony_ci	if (chan->state != BT_CONNECTED) {
52488c2ecf20Sopenharmony_ci		l2cap_do_create(chan, result, local_amp_id, remote_amp_id);
52498c2ecf20Sopenharmony_ci	} else if (result != L2CAP_MR_SUCCESS) {
52508c2ecf20Sopenharmony_ci		l2cap_do_move_cancel(chan, result);
52518c2ecf20Sopenharmony_ci	} else {
52528c2ecf20Sopenharmony_ci		switch (chan->move_role) {
52538c2ecf20Sopenharmony_ci		case L2CAP_MOVE_ROLE_INITIATOR:
52548c2ecf20Sopenharmony_ci			l2cap_do_move_initiate(chan, local_amp_id,
52558c2ecf20Sopenharmony_ci					       remote_amp_id);
52568c2ecf20Sopenharmony_ci			break;
52578c2ecf20Sopenharmony_ci		case L2CAP_MOVE_ROLE_RESPONDER:
52588c2ecf20Sopenharmony_ci			l2cap_do_move_respond(chan, result);
52598c2ecf20Sopenharmony_ci			break;
52608c2ecf20Sopenharmony_ci		default:
52618c2ecf20Sopenharmony_ci			l2cap_do_move_cancel(chan, result);
52628c2ecf20Sopenharmony_ci			break;
52638c2ecf20Sopenharmony_ci		}
52648c2ecf20Sopenharmony_ci	}
52658c2ecf20Sopenharmony_ci}
52668c2ecf20Sopenharmony_ci
52678c2ecf20Sopenharmony_cistatic inline int l2cap_move_channel_req(struct l2cap_conn *conn,
52688c2ecf20Sopenharmony_ci					 struct l2cap_cmd_hdr *cmd,
52698c2ecf20Sopenharmony_ci					 u16 cmd_len, void *data)
52708c2ecf20Sopenharmony_ci{
52718c2ecf20Sopenharmony_ci	struct l2cap_move_chan_req *req = data;
52728c2ecf20Sopenharmony_ci	struct l2cap_move_chan_rsp rsp;
52738c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
52748c2ecf20Sopenharmony_ci	u16 icid = 0;
52758c2ecf20Sopenharmony_ci	u16 result = L2CAP_MR_NOT_ALLOWED;
52768c2ecf20Sopenharmony_ci
52778c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(*req))
52788c2ecf20Sopenharmony_ci		return -EPROTO;
52798c2ecf20Sopenharmony_ci
52808c2ecf20Sopenharmony_ci	icid = le16_to_cpu(req->icid);
52818c2ecf20Sopenharmony_ci
52828c2ecf20Sopenharmony_ci	BT_DBG("icid 0x%4.4x, dest_amp_id %d", icid, req->dest_amp_id);
52838c2ecf20Sopenharmony_ci
52848c2ecf20Sopenharmony_ci	if (!(conn->local_fixed_chan & L2CAP_FC_A2MP))
52858c2ecf20Sopenharmony_ci		return -EINVAL;
52868c2ecf20Sopenharmony_ci
52878c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_dcid(conn, icid);
52888c2ecf20Sopenharmony_ci	if (!chan) {
52898c2ecf20Sopenharmony_ci		rsp.icid = cpu_to_le16(icid);
52908c2ecf20Sopenharmony_ci		rsp.result = cpu_to_le16(L2CAP_MR_NOT_ALLOWED);
52918c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, cmd->ident, L2CAP_MOVE_CHAN_RSP,
52928c2ecf20Sopenharmony_ci			       sizeof(rsp), &rsp);
52938c2ecf20Sopenharmony_ci		return 0;
52948c2ecf20Sopenharmony_ci	}
52958c2ecf20Sopenharmony_ci
52968c2ecf20Sopenharmony_ci	chan->ident = cmd->ident;
52978c2ecf20Sopenharmony_ci
52988c2ecf20Sopenharmony_ci	if (chan->scid < L2CAP_CID_DYN_START ||
52998c2ecf20Sopenharmony_ci	    chan->chan_policy == BT_CHANNEL_POLICY_BREDR_ONLY ||
53008c2ecf20Sopenharmony_ci	    (chan->mode != L2CAP_MODE_ERTM &&
53018c2ecf20Sopenharmony_ci	     chan->mode != L2CAP_MODE_STREAMING)) {
53028c2ecf20Sopenharmony_ci		result = L2CAP_MR_NOT_ALLOWED;
53038c2ecf20Sopenharmony_ci		goto send_move_response;
53048c2ecf20Sopenharmony_ci	}
53058c2ecf20Sopenharmony_ci
53068c2ecf20Sopenharmony_ci	if (chan->local_amp_id == req->dest_amp_id) {
53078c2ecf20Sopenharmony_ci		result = L2CAP_MR_SAME_ID;
53088c2ecf20Sopenharmony_ci		goto send_move_response;
53098c2ecf20Sopenharmony_ci	}
53108c2ecf20Sopenharmony_ci
53118c2ecf20Sopenharmony_ci	if (req->dest_amp_id != AMP_ID_BREDR) {
53128c2ecf20Sopenharmony_ci		struct hci_dev *hdev;
53138c2ecf20Sopenharmony_ci		hdev = hci_dev_get(req->dest_amp_id);
53148c2ecf20Sopenharmony_ci		if (!hdev || hdev->dev_type != HCI_AMP ||
53158c2ecf20Sopenharmony_ci		    !test_bit(HCI_UP, &hdev->flags)) {
53168c2ecf20Sopenharmony_ci			if (hdev)
53178c2ecf20Sopenharmony_ci				hci_dev_put(hdev);
53188c2ecf20Sopenharmony_ci
53198c2ecf20Sopenharmony_ci			result = L2CAP_MR_BAD_ID;
53208c2ecf20Sopenharmony_ci			goto send_move_response;
53218c2ecf20Sopenharmony_ci		}
53228c2ecf20Sopenharmony_ci		hci_dev_put(hdev);
53238c2ecf20Sopenharmony_ci	}
53248c2ecf20Sopenharmony_ci
53258c2ecf20Sopenharmony_ci	/* Detect a move collision.  Only send a collision response
53268c2ecf20Sopenharmony_ci	 * if this side has "lost", otherwise proceed with the move.
53278c2ecf20Sopenharmony_ci	 * The winner has the larger bd_addr.
53288c2ecf20Sopenharmony_ci	 */
53298c2ecf20Sopenharmony_ci	if ((__chan_is_moving(chan) ||
53308c2ecf20Sopenharmony_ci	     chan->move_role != L2CAP_MOVE_ROLE_NONE) &&
53318c2ecf20Sopenharmony_ci	    bacmp(&conn->hcon->src, &conn->hcon->dst) > 0) {
53328c2ecf20Sopenharmony_ci		result = L2CAP_MR_COLLISION;
53338c2ecf20Sopenharmony_ci		goto send_move_response;
53348c2ecf20Sopenharmony_ci	}
53358c2ecf20Sopenharmony_ci
53368c2ecf20Sopenharmony_ci	chan->move_role = L2CAP_MOVE_ROLE_RESPONDER;
53378c2ecf20Sopenharmony_ci	l2cap_move_setup(chan);
53388c2ecf20Sopenharmony_ci	chan->move_id = req->dest_amp_id;
53398c2ecf20Sopenharmony_ci
53408c2ecf20Sopenharmony_ci	if (req->dest_amp_id == AMP_ID_BREDR) {
53418c2ecf20Sopenharmony_ci		/* Moving to BR/EDR */
53428c2ecf20Sopenharmony_ci		if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
53438c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
53448c2ecf20Sopenharmony_ci			result = L2CAP_MR_PEND;
53458c2ecf20Sopenharmony_ci		} else {
53468c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
53478c2ecf20Sopenharmony_ci			result = L2CAP_MR_SUCCESS;
53488c2ecf20Sopenharmony_ci		}
53498c2ecf20Sopenharmony_ci	} else {
53508c2ecf20Sopenharmony_ci		chan->move_state = L2CAP_MOVE_WAIT_PREPARE;
53518c2ecf20Sopenharmony_ci		/* Placeholder - uncomment when amp functions are available */
53528c2ecf20Sopenharmony_ci		/*amp_accept_physical(chan, req->dest_amp_id);*/
53538c2ecf20Sopenharmony_ci		result = L2CAP_MR_PEND;
53548c2ecf20Sopenharmony_ci	}
53558c2ecf20Sopenharmony_ci
53568c2ecf20Sopenharmony_cisend_move_response:
53578c2ecf20Sopenharmony_ci	l2cap_send_move_chan_rsp(chan, result);
53588c2ecf20Sopenharmony_ci
53598c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
53608c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
53618c2ecf20Sopenharmony_ci
53628c2ecf20Sopenharmony_ci	return 0;
53638c2ecf20Sopenharmony_ci}
53648c2ecf20Sopenharmony_ci
53658c2ecf20Sopenharmony_cistatic void l2cap_move_continue(struct l2cap_conn *conn, u16 icid, u16 result)
53668c2ecf20Sopenharmony_ci{
53678c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
53688c2ecf20Sopenharmony_ci	struct hci_chan *hchan = NULL;
53698c2ecf20Sopenharmony_ci
53708c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_scid(conn, icid);
53718c2ecf20Sopenharmony_ci	if (!chan) {
53728c2ecf20Sopenharmony_ci		l2cap_send_move_chan_cfm_icid(conn, icid);
53738c2ecf20Sopenharmony_ci		return;
53748c2ecf20Sopenharmony_ci	}
53758c2ecf20Sopenharmony_ci
53768c2ecf20Sopenharmony_ci	__clear_chan_timer(chan);
53778c2ecf20Sopenharmony_ci	if (result == L2CAP_MR_PEND)
53788c2ecf20Sopenharmony_ci		__set_chan_timer(chan, L2CAP_MOVE_ERTX_TIMEOUT);
53798c2ecf20Sopenharmony_ci
53808c2ecf20Sopenharmony_ci	switch (chan->move_state) {
53818c2ecf20Sopenharmony_ci	case L2CAP_MOVE_WAIT_LOGICAL_COMP:
53828c2ecf20Sopenharmony_ci		/* Move confirm will be sent when logical link
53838c2ecf20Sopenharmony_ci		 * is complete.
53848c2ecf20Sopenharmony_ci		 */
53858c2ecf20Sopenharmony_ci		chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM;
53868c2ecf20Sopenharmony_ci		break;
53878c2ecf20Sopenharmony_ci	case L2CAP_MOVE_WAIT_RSP_SUCCESS:
53888c2ecf20Sopenharmony_ci		if (result == L2CAP_MR_PEND) {
53898c2ecf20Sopenharmony_ci			break;
53908c2ecf20Sopenharmony_ci		} else if (test_bit(CONN_LOCAL_BUSY,
53918c2ecf20Sopenharmony_ci				    &chan->conn_state)) {
53928c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
53938c2ecf20Sopenharmony_ci		} else {
53948c2ecf20Sopenharmony_ci			/* Logical link is up or moving to BR/EDR,
53958c2ecf20Sopenharmony_ci			 * proceed with move
53968c2ecf20Sopenharmony_ci			 */
53978c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP;
53988c2ecf20Sopenharmony_ci			l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED);
53998c2ecf20Sopenharmony_ci		}
54008c2ecf20Sopenharmony_ci		break;
54018c2ecf20Sopenharmony_ci	case L2CAP_MOVE_WAIT_RSP:
54028c2ecf20Sopenharmony_ci		/* Moving to AMP */
54038c2ecf20Sopenharmony_ci		if (result == L2CAP_MR_SUCCESS) {
54048c2ecf20Sopenharmony_ci			/* Remote is ready, send confirm immediately
54058c2ecf20Sopenharmony_ci			 * after logical link is ready
54068c2ecf20Sopenharmony_ci			 */
54078c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM;
54088c2ecf20Sopenharmony_ci		} else {
54098c2ecf20Sopenharmony_ci			/* Both logical link and move success
54108c2ecf20Sopenharmony_ci			 * are required to confirm
54118c2ecf20Sopenharmony_ci			 */
54128c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_COMP;
54138c2ecf20Sopenharmony_ci		}
54148c2ecf20Sopenharmony_ci
54158c2ecf20Sopenharmony_ci		/* Placeholder - get hci_chan for logical link */
54168c2ecf20Sopenharmony_ci		if (!hchan) {
54178c2ecf20Sopenharmony_ci			/* Logical link not available */
54188c2ecf20Sopenharmony_ci			l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
54198c2ecf20Sopenharmony_ci			break;
54208c2ecf20Sopenharmony_ci		}
54218c2ecf20Sopenharmony_ci
54228c2ecf20Sopenharmony_ci		/* If the logical link is not yet connected, do not
54238c2ecf20Sopenharmony_ci		 * send confirmation.
54248c2ecf20Sopenharmony_ci		 */
54258c2ecf20Sopenharmony_ci		if (hchan->state != BT_CONNECTED)
54268c2ecf20Sopenharmony_ci			break;
54278c2ecf20Sopenharmony_ci
54288c2ecf20Sopenharmony_ci		/* Logical link is already ready to go */
54298c2ecf20Sopenharmony_ci
54308c2ecf20Sopenharmony_ci		chan->hs_hcon = hchan->conn;
54318c2ecf20Sopenharmony_ci		chan->hs_hcon->l2cap_data = chan->conn;
54328c2ecf20Sopenharmony_ci
54338c2ecf20Sopenharmony_ci		if (result == L2CAP_MR_SUCCESS) {
54348c2ecf20Sopenharmony_ci			/* Can confirm now */
54358c2ecf20Sopenharmony_ci			l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED);
54368c2ecf20Sopenharmony_ci		} else {
54378c2ecf20Sopenharmony_ci			/* Now only need move success
54388c2ecf20Sopenharmony_ci			 * to confirm
54398c2ecf20Sopenharmony_ci			 */
54408c2ecf20Sopenharmony_ci			chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
54418c2ecf20Sopenharmony_ci		}
54428c2ecf20Sopenharmony_ci
54438c2ecf20Sopenharmony_ci		l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS);
54448c2ecf20Sopenharmony_ci		break;
54458c2ecf20Sopenharmony_ci	default:
54468c2ecf20Sopenharmony_ci		/* Any other amp move state means the move failed. */
54478c2ecf20Sopenharmony_ci		chan->move_id = chan->local_amp_id;
54488c2ecf20Sopenharmony_ci		l2cap_move_done(chan);
54498c2ecf20Sopenharmony_ci		l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
54508c2ecf20Sopenharmony_ci	}
54518c2ecf20Sopenharmony_ci
54528c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
54538c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
54548c2ecf20Sopenharmony_ci}
54558c2ecf20Sopenharmony_ci
54568c2ecf20Sopenharmony_cistatic void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid,
54578c2ecf20Sopenharmony_ci			    u16 result)
54588c2ecf20Sopenharmony_ci{
54598c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
54608c2ecf20Sopenharmony_ci
54618c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_ident(conn, ident);
54628c2ecf20Sopenharmony_ci	if (!chan) {
54638c2ecf20Sopenharmony_ci		/* Could not locate channel, icid is best guess */
54648c2ecf20Sopenharmony_ci		l2cap_send_move_chan_cfm_icid(conn, icid);
54658c2ecf20Sopenharmony_ci		return;
54668c2ecf20Sopenharmony_ci	}
54678c2ecf20Sopenharmony_ci
54688c2ecf20Sopenharmony_ci	__clear_chan_timer(chan);
54698c2ecf20Sopenharmony_ci
54708c2ecf20Sopenharmony_ci	if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
54718c2ecf20Sopenharmony_ci		if (result == L2CAP_MR_COLLISION) {
54728c2ecf20Sopenharmony_ci			chan->move_role = L2CAP_MOVE_ROLE_RESPONDER;
54738c2ecf20Sopenharmony_ci		} else {
54748c2ecf20Sopenharmony_ci			/* Cleanup - cancel move */
54758c2ecf20Sopenharmony_ci			chan->move_id = chan->local_amp_id;
54768c2ecf20Sopenharmony_ci			l2cap_move_done(chan);
54778c2ecf20Sopenharmony_ci		}
54788c2ecf20Sopenharmony_ci	}
54798c2ecf20Sopenharmony_ci
54808c2ecf20Sopenharmony_ci	l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
54818c2ecf20Sopenharmony_ci
54828c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
54838c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
54848c2ecf20Sopenharmony_ci}
54858c2ecf20Sopenharmony_ci
54868c2ecf20Sopenharmony_cistatic int l2cap_move_channel_rsp(struct l2cap_conn *conn,
54878c2ecf20Sopenharmony_ci				  struct l2cap_cmd_hdr *cmd,
54888c2ecf20Sopenharmony_ci				  u16 cmd_len, void *data)
54898c2ecf20Sopenharmony_ci{
54908c2ecf20Sopenharmony_ci	struct l2cap_move_chan_rsp *rsp = data;
54918c2ecf20Sopenharmony_ci	u16 icid, result;
54928c2ecf20Sopenharmony_ci
54938c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(*rsp))
54948c2ecf20Sopenharmony_ci		return -EPROTO;
54958c2ecf20Sopenharmony_ci
54968c2ecf20Sopenharmony_ci	icid = le16_to_cpu(rsp->icid);
54978c2ecf20Sopenharmony_ci	result = le16_to_cpu(rsp->result);
54988c2ecf20Sopenharmony_ci
54998c2ecf20Sopenharmony_ci	BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result);
55008c2ecf20Sopenharmony_ci
55018c2ecf20Sopenharmony_ci	if (result == L2CAP_MR_SUCCESS || result == L2CAP_MR_PEND)
55028c2ecf20Sopenharmony_ci		l2cap_move_continue(conn, icid, result);
55038c2ecf20Sopenharmony_ci	else
55048c2ecf20Sopenharmony_ci		l2cap_move_fail(conn, cmd->ident, icid, result);
55058c2ecf20Sopenharmony_ci
55068c2ecf20Sopenharmony_ci	return 0;
55078c2ecf20Sopenharmony_ci}
55088c2ecf20Sopenharmony_ci
55098c2ecf20Sopenharmony_cistatic int l2cap_move_channel_confirm(struct l2cap_conn *conn,
55108c2ecf20Sopenharmony_ci				      struct l2cap_cmd_hdr *cmd,
55118c2ecf20Sopenharmony_ci				      u16 cmd_len, void *data)
55128c2ecf20Sopenharmony_ci{
55138c2ecf20Sopenharmony_ci	struct l2cap_move_chan_cfm *cfm = data;
55148c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
55158c2ecf20Sopenharmony_ci	u16 icid, result;
55168c2ecf20Sopenharmony_ci
55178c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(*cfm))
55188c2ecf20Sopenharmony_ci		return -EPROTO;
55198c2ecf20Sopenharmony_ci
55208c2ecf20Sopenharmony_ci	icid = le16_to_cpu(cfm->icid);
55218c2ecf20Sopenharmony_ci	result = le16_to_cpu(cfm->result);
55228c2ecf20Sopenharmony_ci
55238c2ecf20Sopenharmony_ci	BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result);
55248c2ecf20Sopenharmony_ci
55258c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_dcid(conn, icid);
55268c2ecf20Sopenharmony_ci	if (!chan) {
55278c2ecf20Sopenharmony_ci		/* Spec requires a response even if the icid was not found */
55288c2ecf20Sopenharmony_ci		l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
55298c2ecf20Sopenharmony_ci		return 0;
55308c2ecf20Sopenharmony_ci	}
55318c2ecf20Sopenharmony_ci
55328c2ecf20Sopenharmony_ci	if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM) {
55338c2ecf20Sopenharmony_ci		if (result == L2CAP_MC_CONFIRMED) {
55348c2ecf20Sopenharmony_ci			chan->local_amp_id = chan->move_id;
55358c2ecf20Sopenharmony_ci			if (chan->local_amp_id == AMP_ID_BREDR)
55368c2ecf20Sopenharmony_ci				__release_logical_link(chan);
55378c2ecf20Sopenharmony_ci		} else {
55388c2ecf20Sopenharmony_ci			chan->move_id = chan->local_amp_id;
55398c2ecf20Sopenharmony_ci		}
55408c2ecf20Sopenharmony_ci
55418c2ecf20Sopenharmony_ci		l2cap_move_done(chan);
55428c2ecf20Sopenharmony_ci	}
55438c2ecf20Sopenharmony_ci
55448c2ecf20Sopenharmony_ci	l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
55458c2ecf20Sopenharmony_ci
55468c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
55478c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
55488c2ecf20Sopenharmony_ci
55498c2ecf20Sopenharmony_ci	return 0;
55508c2ecf20Sopenharmony_ci}
55518c2ecf20Sopenharmony_ci
55528c2ecf20Sopenharmony_cistatic inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
55538c2ecf20Sopenharmony_ci						 struct l2cap_cmd_hdr *cmd,
55548c2ecf20Sopenharmony_ci						 u16 cmd_len, void *data)
55558c2ecf20Sopenharmony_ci{
55568c2ecf20Sopenharmony_ci	struct l2cap_move_chan_cfm_rsp *rsp = data;
55578c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
55588c2ecf20Sopenharmony_ci	u16 icid;
55598c2ecf20Sopenharmony_ci
55608c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(*rsp))
55618c2ecf20Sopenharmony_ci		return -EPROTO;
55628c2ecf20Sopenharmony_ci
55638c2ecf20Sopenharmony_ci	icid = le16_to_cpu(rsp->icid);
55648c2ecf20Sopenharmony_ci
55658c2ecf20Sopenharmony_ci	BT_DBG("icid 0x%4.4x", icid);
55668c2ecf20Sopenharmony_ci
55678c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_scid(conn, icid);
55688c2ecf20Sopenharmony_ci	if (!chan)
55698c2ecf20Sopenharmony_ci		return 0;
55708c2ecf20Sopenharmony_ci
55718c2ecf20Sopenharmony_ci	__clear_chan_timer(chan);
55728c2ecf20Sopenharmony_ci
55738c2ecf20Sopenharmony_ci	if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM_RSP) {
55748c2ecf20Sopenharmony_ci		chan->local_amp_id = chan->move_id;
55758c2ecf20Sopenharmony_ci
55768c2ecf20Sopenharmony_ci		if (chan->local_amp_id == AMP_ID_BREDR && chan->hs_hchan)
55778c2ecf20Sopenharmony_ci			__release_logical_link(chan);
55788c2ecf20Sopenharmony_ci
55798c2ecf20Sopenharmony_ci		l2cap_move_done(chan);
55808c2ecf20Sopenharmony_ci	}
55818c2ecf20Sopenharmony_ci
55828c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
55838c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
55848c2ecf20Sopenharmony_ci
55858c2ecf20Sopenharmony_ci	return 0;
55868c2ecf20Sopenharmony_ci}
55878c2ecf20Sopenharmony_ci
55888c2ecf20Sopenharmony_cistatic inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
55898c2ecf20Sopenharmony_ci					      struct l2cap_cmd_hdr *cmd,
55908c2ecf20Sopenharmony_ci					      u16 cmd_len, u8 *data)
55918c2ecf20Sopenharmony_ci{
55928c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
55938c2ecf20Sopenharmony_ci	struct l2cap_conn_param_update_req *req;
55948c2ecf20Sopenharmony_ci	struct l2cap_conn_param_update_rsp rsp;
55958c2ecf20Sopenharmony_ci	u16 min, max, latency, to_multiplier;
55968c2ecf20Sopenharmony_ci	int err;
55978c2ecf20Sopenharmony_ci
55988c2ecf20Sopenharmony_ci	if (hcon->role != HCI_ROLE_MASTER)
55998c2ecf20Sopenharmony_ci		return -EINVAL;
56008c2ecf20Sopenharmony_ci
56018c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
56028c2ecf20Sopenharmony_ci		return -EPROTO;
56038c2ecf20Sopenharmony_ci
56048c2ecf20Sopenharmony_ci	req = (struct l2cap_conn_param_update_req *) data;
56058c2ecf20Sopenharmony_ci	min		= __le16_to_cpu(req->min);
56068c2ecf20Sopenharmony_ci	max		= __le16_to_cpu(req->max);
56078c2ecf20Sopenharmony_ci	latency		= __le16_to_cpu(req->latency);
56088c2ecf20Sopenharmony_ci	to_multiplier	= __le16_to_cpu(req->to_multiplier);
56098c2ecf20Sopenharmony_ci
56108c2ecf20Sopenharmony_ci	BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
56118c2ecf20Sopenharmony_ci	       min, max, latency, to_multiplier);
56128c2ecf20Sopenharmony_ci
56138c2ecf20Sopenharmony_ci	memset(&rsp, 0, sizeof(rsp));
56148c2ecf20Sopenharmony_ci
56158c2ecf20Sopenharmony_ci	err = hci_check_conn_params(min, max, latency, to_multiplier);
56168c2ecf20Sopenharmony_ci	if (err)
56178c2ecf20Sopenharmony_ci		rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
56188c2ecf20Sopenharmony_ci	else
56198c2ecf20Sopenharmony_ci		rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
56208c2ecf20Sopenharmony_ci
56218c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
56228c2ecf20Sopenharmony_ci		       sizeof(rsp), &rsp);
56238c2ecf20Sopenharmony_ci
56248c2ecf20Sopenharmony_ci	if (!err) {
56258c2ecf20Sopenharmony_ci		u8 store_hint;
56268c2ecf20Sopenharmony_ci
56278c2ecf20Sopenharmony_ci		store_hint = hci_le_conn_update(hcon, min, max, latency,
56288c2ecf20Sopenharmony_ci						to_multiplier);
56298c2ecf20Sopenharmony_ci		mgmt_new_conn_param(hcon->hdev, &hcon->dst, hcon->dst_type,
56308c2ecf20Sopenharmony_ci				    store_hint, min, max, latency,
56318c2ecf20Sopenharmony_ci				    to_multiplier);
56328c2ecf20Sopenharmony_ci
56338c2ecf20Sopenharmony_ci	}
56348c2ecf20Sopenharmony_ci
56358c2ecf20Sopenharmony_ci	return 0;
56368c2ecf20Sopenharmony_ci}
56378c2ecf20Sopenharmony_ci
56388c2ecf20Sopenharmony_cistatic int l2cap_le_connect_rsp(struct l2cap_conn *conn,
56398c2ecf20Sopenharmony_ci				struct l2cap_cmd_hdr *cmd, u16 cmd_len,
56408c2ecf20Sopenharmony_ci				u8 *data)
56418c2ecf20Sopenharmony_ci{
56428c2ecf20Sopenharmony_ci	struct l2cap_le_conn_rsp *rsp = (struct l2cap_le_conn_rsp *) data;
56438c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
56448c2ecf20Sopenharmony_ci	u16 dcid, mtu, mps, credits, result;
56458c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
56468c2ecf20Sopenharmony_ci	int err, sec_level;
56478c2ecf20Sopenharmony_ci
56488c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*rsp))
56498c2ecf20Sopenharmony_ci		return -EPROTO;
56508c2ecf20Sopenharmony_ci
56518c2ecf20Sopenharmony_ci	dcid    = __le16_to_cpu(rsp->dcid);
56528c2ecf20Sopenharmony_ci	mtu     = __le16_to_cpu(rsp->mtu);
56538c2ecf20Sopenharmony_ci	mps     = __le16_to_cpu(rsp->mps);
56548c2ecf20Sopenharmony_ci	credits = __le16_to_cpu(rsp->credits);
56558c2ecf20Sopenharmony_ci	result  = __le16_to_cpu(rsp->result);
56568c2ecf20Sopenharmony_ci
56578c2ecf20Sopenharmony_ci	if (result == L2CAP_CR_LE_SUCCESS && (mtu < 23 || mps < 23 ||
56588c2ecf20Sopenharmony_ci					   dcid < L2CAP_CID_DYN_START ||
56598c2ecf20Sopenharmony_ci					   dcid > L2CAP_CID_LE_DYN_END))
56608c2ecf20Sopenharmony_ci		return -EPROTO;
56618c2ecf20Sopenharmony_ci
56628c2ecf20Sopenharmony_ci	BT_DBG("dcid 0x%4.4x mtu %u mps %u credits %u result 0x%2.2x",
56638c2ecf20Sopenharmony_ci	       dcid, mtu, mps, credits, result);
56648c2ecf20Sopenharmony_ci
56658c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
56668c2ecf20Sopenharmony_ci
56678c2ecf20Sopenharmony_ci	chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
56688c2ecf20Sopenharmony_ci	if (!chan) {
56698c2ecf20Sopenharmony_ci		err = -EBADSLT;
56708c2ecf20Sopenharmony_ci		goto unlock;
56718c2ecf20Sopenharmony_ci	}
56728c2ecf20Sopenharmony_ci
56738c2ecf20Sopenharmony_ci	err = 0;
56748c2ecf20Sopenharmony_ci
56758c2ecf20Sopenharmony_ci	l2cap_chan_lock(chan);
56768c2ecf20Sopenharmony_ci
56778c2ecf20Sopenharmony_ci	switch (result) {
56788c2ecf20Sopenharmony_ci	case L2CAP_CR_LE_SUCCESS:
56798c2ecf20Sopenharmony_ci		if (__l2cap_get_chan_by_dcid(conn, dcid)) {
56808c2ecf20Sopenharmony_ci			err = -EBADSLT;
56818c2ecf20Sopenharmony_ci			break;
56828c2ecf20Sopenharmony_ci		}
56838c2ecf20Sopenharmony_ci
56848c2ecf20Sopenharmony_ci		chan->ident = 0;
56858c2ecf20Sopenharmony_ci		chan->dcid = dcid;
56868c2ecf20Sopenharmony_ci		chan->omtu = mtu;
56878c2ecf20Sopenharmony_ci		chan->remote_mps = mps;
56888c2ecf20Sopenharmony_ci		chan->tx_credits = credits;
56898c2ecf20Sopenharmony_ci		l2cap_chan_ready(chan);
56908c2ecf20Sopenharmony_ci		break;
56918c2ecf20Sopenharmony_ci
56928c2ecf20Sopenharmony_ci	case L2CAP_CR_LE_AUTHENTICATION:
56938c2ecf20Sopenharmony_ci	case L2CAP_CR_LE_ENCRYPTION:
56948c2ecf20Sopenharmony_ci		/* If we already have MITM protection we can't do
56958c2ecf20Sopenharmony_ci		 * anything.
56968c2ecf20Sopenharmony_ci		 */
56978c2ecf20Sopenharmony_ci		if (hcon->sec_level > BT_SECURITY_MEDIUM) {
56988c2ecf20Sopenharmony_ci			l2cap_chan_del(chan, ECONNREFUSED);
56998c2ecf20Sopenharmony_ci			break;
57008c2ecf20Sopenharmony_ci		}
57018c2ecf20Sopenharmony_ci
57028c2ecf20Sopenharmony_ci		sec_level = hcon->sec_level + 1;
57038c2ecf20Sopenharmony_ci		if (chan->sec_level < sec_level)
57048c2ecf20Sopenharmony_ci			chan->sec_level = sec_level;
57058c2ecf20Sopenharmony_ci
57068c2ecf20Sopenharmony_ci		/* We'll need to send a new Connect Request */
57078c2ecf20Sopenharmony_ci		clear_bit(FLAG_LE_CONN_REQ_SENT, &chan->flags);
57088c2ecf20Sopenharmony_ci
57098c2ecf20Sopenharmony_ci		smp_conn_security(hcon, chan->sec_level);
57108c2ecf20Sopenharmony_ci		break;
57118c2ecf20Sopenharmony_ci
57128c2ecf20Sopenharmony_ci	default:
57138c2ecf20Sopenharmony_ci		l2cap_chan_del(chan, ECONNREFUSED);
57148c2ecf20Sopenharmony_ci		break;
57158c2ecf20Sopenharmony_ci	}
57168c2ecf20Sopenharmony_ci
57178c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
57188c2ecf20Sopenharmony_ci
57198c2ecf20Sopenharmony_ciunlock:
57208c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
57218c2ecf20Sopenharmony_ci
57228c2ecf20Sopenharmony_ci	return err;
57238c2ecf20Sopenharmony_ci}
57248c2ecf20Sopenharmony_ci
57258c2ecf20Sopenharmony_cistatic inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
57268c2ecf20Sopenharmony_ci				      struct l2cap_cmd_hdr *cmd, u16 cmd_len,
57278c2ecf20Sopenharmony_ci				      u8 *data)
57288c2ecf20Sopenharmony_ci{
57298c2ecf20Sopenharmony_ci	int err = 0;
57308c2ecf20Sopenharmony_ci
57318c2ecf20Sopenharmony_ci	switch (cmd->code) {
57328c2ecf20Sopenharmony_ci	case L2CAP_COMMAND_REJ:
57338c2ecf20Sopenharmony_ci		l2cap_command_rej(conn, cmd, cmd_len, data);
57348c2ecf20Sopenharmony_ci		break;
57358c2ecf20Sopenharmony_ci
57368c2ecf20Sopenharmony_ci	case L2CAP_CONN_REQ:
57378c2ecf20Sopenharmony_ci		err = l2cap_connect_req(conn, cmd, cmd_len, data);
57388c2ecf20Sopenharmony_ci		break;
57398c2ecf20Sopenharmony_ci
57408c2ecf20Sopenharmony_ci	case L2CAP_CONN_RSP:
57418c2ecf20Sopenharmony_ci	case L2CAP_CREATE_CHAN_RSP:
57428c2ecf20Sopenharmony_ci		l2cap_connect_create_rsp(conn, cmd, cmd_len, data);
57438c2ecf20Sopenharmony_ci		break;
57448c2ecf20Sopenharmony_ci
57458c2ecf20Sopenharmony_ci	case L2CAP_CONF_REQ:
57468c2ecf20Sopenharmony_ci		err = l2cap_config_req(conn, cmd, cmd_len, data);
57478c2ecf20Sopenharmony_ci		break;
57488c2ecf20Sopenharmony_ci
57498c2ecf20Sopenharmony_ci	case L2CAP_CONF_RSP:
57508c2ecf20Sopenharmony_ci		l2cap_config_rsp(conn, cmd, cmd_len, data);
57518c2ecf20Sopenharmony_ci		break;
57528c2ecf20Sopenharmony_ci
57538c2ecf20Sopenharmony_ci	case L2CAP_DISCONN_REQ:
57548c2ecf20Sopenharmony_ci		err = l2cap_disconnect_req(conn, cmd, cmd_len, data);
57558c2ecf20Sopenharmony_ci		break;
57568c2ecf20Sopenharmony_ci
57578c2ecf20Sopenharmony_ci	case L2CAP_DISCONN_RSP:
57588c2ecf20Sopenharmony_ci		l2cap_disconnect_rsp(conn, cmd, cmd_len, data);
57598c2ecf20Sopenharmony_ci		break;
57608c2ecf20Sopenharmony_ci
57618c2ecf20Sopenharmony_ci	case L2CAP_ECHO_REQ:
57628c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
57638c2ecf20Sopenharmony_ci		break;
57648c2ecf20Sopenharmony_ci
57658c2ecf20Sopenharmony_ci	case L2CAP_ECHO_RSP:
57668c2ecf20Sopenharmony_ci		break;
57678c2ecf20Sopenharmony_ci
57688c2ecf20Sopenharmony_ci	case L2CAP_INFO_REQ:
57698c2ecf20Sopenharmony_ci		err = l2cap_information_req(conn, cmd, cmd_len, data);
57708c2ecf20Sopenharmony_ci		break;
57718c2ecf20Sopenharmony_ci
57728c2ecf20Sopenharmony_ci	case L2CAP_INFO_RSP:
57738c2ecf20Sopenharmony_ci		l2cap_information_rsp(conn, cmd, cmd_len, data);
57748c2ecf20Sopenharmony_ci		break;
57758c2ecf20Sopenharmony_ci
57768c2ecf20Sopenharmony_ci	case L2CAP_CREATE_CHAN_REQ:
57778c2ecf20Sopenharmony_ci		err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
57788c2ecf20Sopenharmony_ci		break;
57798c2ecf20Sopenharmony_ci
57808c2ecf20Sopenharmony_ci	case L2CAP_MOVE_CHAN_REQ:
57818c2ecf20Sopenharmony_ci		err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
57828c2ecf20Sopenharmony_ci		break;
57838c2ecf20Sopenharmony_ci
57848c2ecf20Sopenharmony_ci	case L2CAP_MOVE_CHAN_RSP:
57858c2ecf20Sopenharmony_ci		l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
57868c2ecf20Sopenharmony_ci		break;
57878c2ecf20Sopenharmony_ci
57888c2ecf20Sopenharmony_ci	case L2CAP_MOVE_CHAN_CFM:
57898c2ecf20Sopenharmony_ci		err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
57908c2ecf20Sopenharmony_ci		break;
57918c2ecf20Sopenharmony_ci
57928c2ecf20Sopenharmony_ci	case L2CAP_MOVE_CHAN_CFM_RSP:
57938c2ecf20Sopenharmony_ci		l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
57948c2ecf20Sopenharmony_ci		break;
57958c2ecf20Sopenharmony_ci
57968c2ecf20Sopenharmony_ci	default:
57978c2ecf20Sopenharmony_ci		BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
57988c2ecf20Sopenharmony_ci		err = -EINVAL;
57998c2ecf20Sopenharmony_ci		break;
58008c2ecf20Sopenharmony_ci	}
58018c2ecf20Sopenharmony_ci
58028c2ecf20Sopenharmony_ci	return err;
58038c2ecf20Sopenharmony_ci}
58048c2ecf20Sopenharmony_ci
58058c2ecf20Sopenharmony_cistatic int l2cap_le_connect_req(struct l2cap_conn *conn,
58068c2ecf20Sopenharmony_ci				struct l2cap_cmd_hdr *cmd, u16 cmd_len,
58078c2ecf20Sopenharmony_ci				u8 *data)
58088c2ecf20Sopenharmony_ci{
58098c2ecf20Sopenharmony_ci	struct l2cap_le_conn_req *req = (struct l2cap_le_conn_req *) data;
58108c2ecf20Sopenharmony_ci	struct l2cap_le_conn_rsp rsp;
58118c2ecf20Sopenharmony_ci	struct l2cap_chan *chan, *pchan;
58128c2ecf20Sopenharmony_ci	u16 dcid, scid, credits, mtu, mps;
58138c2ecf20Sopenharmony_ci	__le16 psm;
58148c2ecf20Sopenharmony_ci	u8 result;
58158c2ecf20Sopenharmony_ci
58168c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(*req))
58178c2ecf20Sopenharmony_ci		return -EPROTO;
58188c2ecf20Sopenharmony_ci
58198c2ecf20Sopenharmony_ci	scid = __le16_to_cpu(req->scid);
58208c2ecf20Sopenharmony_ci	mtu  = __le16_to_cpu(req->mtu);
58218c2ecf20Sopenharmony_ci	mps  = __le16_to_cpu(req->mps);
58228c2ecf20Sopenharmony_ci	psm  = req->psm;
58238c2ecf20Sopenharmony_ci	dcid = 0;
58248c2ecf20Sopenharmony_ci	credits = 0;
58258c2ecf20Sopenharmony_ci
58268c2ecf20Sopenharmony_ci	if (mtu < 23 || mps < 23)
58278c2ecf20Sopenharmony_ci		return -EPROTO;
58288c2ecf20Sopenharmony_ci
58298c2ecf20Sopenharmony_ci	BT_DBG("psm 0x%2.2x scid 0x%4.4x mtu %u mps %u", __le16_to_cpu(psm),
58308c2ecf20Sopenharmony_ci	       scid, mtu, mps);
58318c2ecf20Sopenharmony_ci
58328c2ecf20Sopenharmony_ci	/* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 3, Part A
58338c2ecf20Sopenharmony_ci	 * page 1059:
58348c2ecf20Sopenharmony_ci	 *
58358c2ecf20Sopenharmony_ci	 * Valid range: 0x0001-0x00ff
58368c2ecf20Sopenharmony_ci	 *
58378c2ecf20Sopenharmony_ci	 * Table 4.15: L2CAP_LE_CREDIT_BASED_CONNECTION_REQ SPSM ranges
58388c2ecf20Sopenharmony_ci	 */
58398c2ecf20Sopenharmony_ci	if (!psm || __le16_to_cpu(psm) > L2CAP_PSM_LE_DYN_END) {
58408c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_BAD_PSM;
58418c2ecf20Sopenharmony_ci		chan = NULL;
58428c2ecf20Sopenharmony_ci		goto response;
58438c2ecf20Sopenharmony_ci	}
58448c2ecf20Sopenharmony_ci
58458c2ecf20Sopenharmony_ci	/* Check if we have socket listening on psm */
58468c2ecf20Sopenharmony_ci	pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src,
58478c2ecf20Sopenharmony_ci					 &conn->hcon->dst, LE_LINK);
58488c2ecf20Sopenharmony_ci	if (!pchan) {
58498c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_BAD_PSM;
58508c2ecf20Sopenharmony_ci		chan = NULL;
58518c2ecf20Sopenharmony_ci		goto response;
58528c2ecf20Sopenharmony_ci	}
58538c2ecf20Sopenharmony_ci
58548c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
58558c2ecf20Sopenharmony_ci	l2cap_chan_lock(pchan);
58568c2ecf20Sopenharmony_ci
58578c2ecf20Sopenharmony_ci	if (!smp_sufficient_security(conn->hcon, pchan->sec_level,
58588c2ecf20Sopenharmony_ci				     SMP_ALLOW_STK)) {
58598c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_AUTHENTICATION;
58608c2ecf20Sopenharmony_ci		chan = NULL;
58618c2ecf20Sopenharmony_ci		goto response_unlock;
58628c2ecf20Sopenharmony_ci	}
58638c2ecf20Sopenharmony_ci
58648c2ecf20Sopenharmony_ci	/* Check for valid dynamic CID range */
58658c2ecf20Sopenharmony_ci	if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
58668c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_INVALID_SCID;
58678c2ecf20Sopenharmony_ci		chan = NULL;
58688c2ecf20Sopenharmony_ci		goto response_unlock;
58698c2ecf20Sopenharmony_ci	}
58708c2ecf20Sopenharmony_ci
58718c2ecf20Sopenharmony_ci	/* Check if we already have channel with that dcid */
58728c2ecf20Sopenharmony_ci	if (__l2cap_get_chan_by_dcid(conn, scid)) {
58738c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_SCID_IN_USE;
58748c2ecf20Sopenharmony_ci		chan = NULL;
58758c2ecf20Sopenharmony_ci		goto response_unlock;
58768c2ecf20Sopenharmony_ci	}
58778c2ecf20Sopenharmony_ci
58788c2ecf20Sopenharmony_ci	chan = pchan->ops->new_connection(pchan);
58798c2ecf20Sopenharmony_ci	if (!chan) {
58808c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_NO_MEM;
58818c2ecf20Sopenharmony_ci		goto response_unlock;
58828c2ecf20Sopenharmony_ci	}
58838c2ecf20Sopenharmony_ci
58848c2ecf20Sopenharmony_ci	bacpy(&chan->src, &conn->hcon->src);
58858c2ecf20Sopenharmony_ci	bacpy(&chan->dst, &conn->hcon->dst);
58868c2ecf20Sopenharmony_ci	chan->src_type = bdaddr_src_type(conn->hcon);
58878c2ecf20Sopenharmony_ci	chan->dst_type = bdaddr_dst_type(conn->hcon);
58888c2ecf20Sopenharmony_ci	chan->psm  = psm;
58898c2ecf20Sopenharmony_ci	chan->dcid = scid;
58908c2ecf20Sopenharmony_ci	chan->omtu = mtu;
58918c2ecf20Sopenharmony_ci	chan->remote_mps = mps;
58928c2ecf20Sopenharmony_ci
58938c2ecf20Sopenharmony_ci	__l2cap_chan_add(conn, chan);
58948c2ecf20Sopenharmony_ci
58958c2ecf20Sopenharmony_ci	l2cap_le_flowctl_init(chan, __le16_to_cpu(req->credits));
58968c2ecf20Sopenharmony_ci
58978c2ecf20Sopenharmony_ci	dcid = chan->scid;
58988c2ecf20Sopenharmony_ci	credits = chan->rx_credits;
58998c2ecf20Sopenharmony_ci
59008c2ecf20Sopenharmony_ci	__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
59018c2ecf20Sopenharmony_ci
59028c2ecf20Sopenharmony_ci	chan->ident = cmd->ident;
59038c2ecf20Sopenharmony_ci
59048c2ecf20Sopenharmony_ci	if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
59058c2ecf20Sopenharmony_ci		l2cap_state_change(chan, BT_CONNECT2);
59068c2ecf20Sopenharmony_ci		/* The following result value is actually not defined
59078c2ecf20Sopenharmony_ci		 * for LE CoC but we use it to let the function know
59088c2ecf20Sopenharmony_ci		 * that it should bail out after doing its cleanup
59098c2ecf20Sopenharmony_ci		 * instead of sending a response.
59108c2ecf20Sopenharmony_ci		 */
59118c2ecf20Sopenharmony_ci		result = L2CAP_CR_PEND;
59128c2ecf20Sopenharmony_ci		chan->ops->defer(chan);
59138c2ecf20Sopenharmony_ci	} else {
59148c2ecf20Sopenharmony_ci		l2cap_chan_ready(chan);
59158c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_SUCCESS;
59168c2ecf20Sopenharmony_ci	}
59178c2ecf20Sopenharmony_ci
59188c2ecf20Sopenharmony_ciresponse_unlock:
59198c2ecf20Sopenharmony_ci	l2cap_chan_unlock(pchan);
59208c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
59218c2ecf20Sopenharmony_ci	l2cap_chan_put(pchan);
59228c2ecf20Sopenharmony_ci
59238c2ecf20Sopenharmony_ci	if (result == L2CAP_CR_PEND)
59248c2ecf20Sopenharmony_ci		return 0;
59258c2ecf20Sopenharmony_ci
59268c2ecf20Sopenharmony_ciresponse:
59278c2ecf20Sopenharmony_ci	if (chan) {
59288c2ecf20Sopenharmony_ci		rsp.mtu = cpu_to_le16(chan->imtu);
59298c2ecf20Sopenharmony_ci		rsp.mps = cpu_to_le16(chan->mps);
59308c2ecf20Sopenharmony_ci	} else {
59318c2ecf20Sopenharmony_ci		rsp.mtu = 0;
59328c2ecf20Sopenharmony_ci		rsp.mps = 0;
59338c2ecf20Sopenharmony_ci	}
59348c2ecf20Sopenharmony_ci
59358c2ecf20Sopenharmony_ci	rsp.dcid    = cpu_to_le16(dcid);
59368c2ecf20Sopenharmony_ci	rsp.credits = cpu_to_le16(credits);
59378c2ecf20Sopenharmony_ci	rsp.result  = cpu_to_le16(result);
59388c2ecf20Sopenharmony_ci
59398c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, cmd->ident, L2CAP_LE_CONN_RSP, sizeof(rsp), &rsp);
59408c2ecf20Sopenharmony_ci
59418c2ecf20Sopenharmony_ci	return 0;
59428c2ecf20Sopenharmony_ci}
59438c2ecf20Sopenharmony_ci
59448c2ecf20Sopenharmony_cistatic inline int l2cap_le_credits(struct l2cap_conn *conn,
59458c2ecf20Sopenharmony_ci				   struct l2cap_cmd_hdr *cmd, u16 cmd_len,
59468c2ecf20Sopenharmony_ci				   u8 *data)
59478c2ecf20Sopenharmony_ci{
59488c2ecf20Sopenharmony_ci	struct l2cap_le_credits *pkt;
59498c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
59508c2ecf20Sopenharmony_ci	u16 cid, credits, max_credits;
59518c2ecf20Sopenharmony_ci
59528c2ecf20Sopenharmony_ci	if (cmd_len != sizeof(*pkt))
59538c2ecf20Sopenharmony_ci		return -EPROTO;
59548c2ecf20Sopenharmony_ci
59558c2ecf20Sopenharmony_ci	pkt = (struct l2cap_le_credits *) data;
59568c2ecf20Sopenharmony_ci	cid	= __le16_to_cpu(pkt->cid);
59578c2ecf20Sopenharmony_ci	credits	= __le16_to_cpu(pkt->credits);
59588c2ecf20Sopenharmony_ci
59598c2ecf20Sopenharmony_ci	BT_DBG("cid 0x%4.4x credits 0x%4.4x", cid, credits);
59608c2ecf20Sopenharmony_ci
59618c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_dcid(conn, cid);
59628c2ecf20Sopenharmony_ci	if (!chan)
59638c2ecf20Sopenharmony_ci		return -EBADSLT;
59648c2ecf20Sopenharmony_ci
59658c2ecf20Sopenharmony_ci	max_credits = LE_FLOWCTL_MAX_CREDITS - chan->tx_credits;
59668c2ecf20Sopenharmony_ci	if (credits > max_credits) {
59678c2ecf20Sopenharmony_ci		BT_ERR("LE credits overflow");
59688c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
59698c2ecf20Sopenharmony_ci
59708c2ecf20Sopenharmony_ci		/* Return 0 so that we don't trigger an unnecessary
59718c2ecf20Sopenharmony_ci		 * command reject packet.
59728c2ecf20Sopenharmony_ci		 */
59738c2ecf20Sopenharmony_ci		goto unlock;
59748c2ecf20Sopenharmony_ci	}
59758c2ecf20Sopenharmony_ci
59768c2ecf20Sopenharmony_ci	chan->tx_credits += credits;
59778c2ecf20Sopenharmony_ci
59788c2ecf20Sopenharmony_ci	/* Resume sending */
59798c2ecf20Sopenharmony_ci	l2cap_le_flowctl_send(chan);
59808c2ecf20Sopenharmony_ci
59818c2ecf20Sopenharmony_ci	if (chan->tx_credits)
59828c2ecf20Sopenharmony_ci		chan->ops->resume(chan);
59838c2ecf20Sopenharmony_ci
59848c2ecf20Sopenharmony_ciunlock:
59858c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
59868c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
59878c2ecf20Sopenharmony_ci
59888c2ecf20Sopenharmony_ci	return 0;
59898c2ecf20Sopenharmony_ci}
59908c2ecf20Sopenharmony_ci
59918c2ecf20Sopenharmony_cistatic inline int l2cap_ecred_conn_req(struct l2cap_conn *conn,
59928c2ecf20Sopenharmony_ci				       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
59938c2ecf20Sopenharmony_ci				       u8 *data)
59948c2ecf20Sopenharmony_ci{
59958c2ecf20Sopenharmony_ci	struct l2cap_ecred_conn_req *req = (void *) data;
59968c2ecf20Sopenharmony_ci	struct {
59978c2ecf20Sopenharmony_ci		struct l2cap_ecred_conn_rsp rsp;
59988c2ecf20Sopenharmony_ci		__le16 dcid[L2CAP_ECRED_MAX_CID];
59998c2ecf20Sopenharmony_ci	} __packed pdu;
60008c2ecf20Sopenharmony_ci	struct l2cap_chan *chan, *pchan;
60018c2ecf20Sopenharmony_ci	u16 mtu, mps;
60028c2ecf20Sopenharmony_ci	__le16 psm;
60038c2ecf20Sopenharmony_ci	u8 result, len = 0;
60048c2ecf20Sopenharmony_ci	int i, num_scid;
60058c2ecf20Sopenharmony_ci	bool defer = false;
60068c2ecf20Sopenharmony_ci
60078c2ecf20Sopenharmony_ci	if (!enable_ecred)
60088c2ecf20Sopenharmony_ci		return -EINVAL;
60098c2ecf20Sopenharmony_ci
60108c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*req) || (cmd_len - sizeof(*req)) % sizeof(u16)) {
60118c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_INVALID_PARAMS;
60128c2ecf20Sopenharmony_ci		goto response;
60138c2ecf20Sopenharmony_ci	}
60148c2ecf20Sopenharmony_ci
60158c2ecf20Sopenharmony_ci	cmd_len -= sizeof(*req);
60168c2ecf20Sopenharmony_ci	num_scid = cmd_len / sizeof(u16);
60178c2ecf20Sopenharmony_ci
60188c2ecf20Sopenharmony_ci	if (num_scid > ARRAY_SIZE(pdu.dcid)) {
60198c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_INVALID_PARAMS;
60208c2ecf20Sopenharmony_ci		goto response;
60218c2ecf20Sopenharmony_ci	}
60228c2ecf20Sopenharmony_ci
60238c2ecf20Sopenharmony_ci	mtu  = __le16_to_cpu(req->mtu);
60248c2ecf20Sopenharmony_ci	mps  = __le16_to_cpu(req->mps);
60258c2ecf20Sopenharmony_ci
60268c2ecf20Sopenharmony_ci	if (mtu < L2CAP_ECRED_MIN_MTU || mps < L2CAP_ECRED_MIN_MPS) {
60278c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_UNACCEPT_PARAMS;
60288c2ecf20Sopenharmony_ci		goto response;
60298c2ecf20Sopenharmony_ci	}
60308c2ecf20Sopenharmony_ci
60318c2ecf20Sopenharmony_ci	psm  = req->psm;
60328c2ecf20Sopenharmony_ci
60338c2ecf20Sopenharmony_ci	/* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 3, Part A
60348c2ecf20Sopenharmony_ci	 * page 1059:
60358c2ecf20Sopenharmony_ci	 *
60368c2ecf20Sopenharmony_ci	 * Valid range: 0x0001-0x00ff
60378c2ecf20Sopenharmony_ci	 *
60388c2ecf20Sopenharmony_ci	 * Table 4.15: L2CAP_LE_CREDIT_BASED_CONNECTION_REQ SPSM ranges
60398c2ecf20Sopenharmony_ci	 */
60408c2ecf20Sopenharmony_ci	if (!psm || __le16_to_cpu(psm) > L2CAP_PSM_LE_DYN_END) {
60418c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_BAD_PSM;
60428c2ecf20Sopenharmony_ci		goto response;
60438c2ecf20Sopenharmony_ci	}
60448c2ecf20Sopenharmony_ci
60458c2ecf20Sopenharmony_ci	BT_DBG("psm 0x%2.2x mtu %u mps %u", __le16_to_cpu(psm), mtu, mps);
60468c2ecf20Sopenharmony_ci
60478c2ecf20Sopenharmony_ci	memset(&pdu, 0, sizeof(pdu));
60488c2ecf20Sopenharmony_ci
60498c2ecf20Sopenharmony_ci	/* Check if we have socket listening on psm */
60508c2ecf20Sopenharmony_ci	pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, &conn->hcon->src,
60518c2ecf20Sopenharmony_ci					 &conn->hcon->dst, LE_LINK);
60528c2ecf20Sopenharmony_ci	if (!pchan) {
60538c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_BAD_PSM;
60548c2ecf20Sopenharmony_ci		goto response;
60558c2ecf20Sopenharmony_ci	}
60568c2ecf20Sopenharmony_ci
60578c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
60588c2ecf20Sopenharmony_ci	l2cap_chan_lock(pchan);
60598c2ecf20Sopenharmony_ci
60608c2ecf20Sopenharmony_ci	if (!smp_sufficient_security(conn->hcon, pchan->sec_level,
60618c2ecf20Sopenharmony_ci				     SMP_ALLOW_STK)) {
60628c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_AUTHENTICATION;
60638c2ecf20Sopenharmony_ci		goto unlock;
60648c2ecf20Sopenharmony_ci	}
60658c2ecf20Sopenharmony_ci
60668c2ecf20Sopenharmony_ci	result = L2CAP_CR_LE_SUCCESS;
60678c2ecf20Sopenharmony_ci
60688c2ecf20Sopenharmony_ci	for (i = 0; i < num_scid; i++) {
60698c2ecf20Sopenharmony_ci		u16 scid = __le16_to_cpu(req->scid[i]);
60708c2ecf20Sopenharmony_ci
60718c2ecf20Sopenharmony_ci		BT_DBG("scid[%d] 0x%4.4x", i, scid);
60728c2ecf20Sopenharmony_ci
60738c2ecf20Sopenharmony_ci		pdu.dcid[i] = 0x0000;
60748c2ecf20Sopenharmony_ci		len += sizeof(*pdu.dcid);
60758c2ecf20Sopenharmony_ci
60768c2ecf20Sopenharmony_ci		/* Check for valid dynamic CID range */
60778c2ecf20Sopenharmony_ci		if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
60788c2ecf20Sopenharmony_ci			result = L2CAP_CR_LE_INVALID_SCID;
60798c2ecf20Sopenharmony_ci			continue;
60808c2ecf20Sopenharmony_ci		}
60818c2ecf20Sopenharmony_ci
60828c2ecf20Sopenharmony_ci		/* Check if we already have channel with that dcid */
60838c2ecf20Sopenharmony_ci		if (__l2cap_get_chan_by_dcid(conn, scid)) {
60848c2ecf20Sopenharmony_ci			result = L2CAP_CR_LE_SCID_IN_USE;
60858c2ecf20Sopenharmony_ci			continue;
60868c2ecf20Sopenharmony_ci		}
60878c2ecf20Sopenharmony_ci
60888c2ecf20Sopenharmony_ci		chan = pchan->ops->new_connection(pchan);
60898c2ecf20Sopenharmony_ci		if (!chan) {
60908c2ecf20Sopenharmony_ci			result = L2CAP_CR_LE_NO_MEM;
60918c2ecf20Sopenharmony_ci			continue;
60928c2ecf20Sopenharmony_ci		}
60938c2ecf20Sopenharmony_ci
60948c2ecf20Sopenharmony_ci		bacpy(&chan->src, &conn->hcon->src);
60958c2ecf20Sopenharmony_ci		bacpy(&chan->dst, &conn->hcon->dst);
60968c2ecf20Sopenharmony_ci		chan->src_type = bdaddr_src_type(conn->hcon);
60978c2ecf20Sopenharmony_ci		chan->dst_type = bdaddr_dst_type(conn->hcon);
60988c2ecf20Sopenharmony_ci		chan->psm  = psm;
60998c2ecf20Sopenharmony_ci		chan->dcid = scid;
61008c2ecf20Sopenharmony_ci		chan->omtu = mtu;
61018c2ecf20Sopenharmony_ci		chan->remote_mps = mps;
61028c2ecf20Sopenharmony_ci
61038c2ecf20Sopenharmony_ci		__l2cap_chan_add(conn, chan);
61048c2ecf20Sopenharmony_ci
61058c2ecf20Sopenharmony_ci		l2cap_ecred_init(chan, __le16_to_cpu(req->credits));
61068c2ecf20Sopenharmony_ci
61078c2ecf20Sopenharmony_ci		/* Init response */
61088c2ecf20Sopenharmony_ci		if (!pdu.rsp.credits) {
61098c2ecf20Sopenharmony_ci			pdu.rsp.mtu = cpu_to_le16(chan->imtu);
61108c2ecf20Sopenharmony_ci			pdu.rsp.mps = cpu_to_le16(chan->mps);
61118c2ecf20Sopenharmony_ci			pdu.rsp.credits = cpu_to_le16(chan->rx_credits);
61128c2ecf20Sopenharmony_ci		}
61138c2ecf20Sopenharmony_ci
61148c2ecf20Sopenharmony_ci		pdu.dcid[i] = cpu_to_le16(chan->scid);
61158c2ecf20Sopenharmony_ci
61168c2ecf20Sopenharmony_ci		__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
61178c2ecf20Sopenharmony_ci
61188c2ecf20Sopenharmony_ci		chan->ident = cmd->ident;
61198c2ecf20Sopenharmony_ci		chan->mode = L2CAP_MODE_EXT_FLOWCTL;
61208c2ecf20Sopenharmony_ci
61218c2ecf20Sopenharmony_ci		if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
61228c2ecf20Sopenharmony_ci			l2cap_state_change(chan, BT_CONNECT2);
61238c2ecf20Sopenharmony_ci			defer = true;
61248c2ecf20Sopenharmony_ci			chan->ops->defer(chan);
61258c2ecf20Sopenharmony_ci		} else {
61268c2ecf20Sopenharmony_ci			l2cap_chan_ready(chan);
61278c2ecf20Sopenharmony_ci		}
61288c2ecf20Sopenharmony_ci	}
61298c2ecf20Sopenharmony_ci
61308c2ecf20Sopenharmony_ciunlock:
61318c2ecf20Sopenharmony_ci	l2cap_chan_unlock(pchan);
61328c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
61338c2ecf20Sopenharmony_ci	l2cap_chan_put(pchan);
61348c2ecf20Sopenharmony_ci
61358c2ecf20Sopenharmony_ciresponse:
61368c2ecf20Sopenharmony_ci	pdu.rsp.result = cpu_to_le16(result);
61378c2ecf20Sopenharmony_ci
61388c2ecf20Sopenharmony_ci	if (defer)
61398c2ecf20Sopenharmony_ci		return 0;
61408c2ecf20Sopenharmony_ci
61418c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, cmd->ident, L2CAP_ECRED_CONN_RSP,
61428c2ecf20Sopenharmony_ci		       sizeof(pdu.rsp) + len, &pdu);
61438c2ecf20Sopenharmony_ci
61448c2ecf20Sopenharmony_ci	return 0;
61458c2ecf20Sopenharmony_ci}
61468c2ecf20Sopenharmony_ci
61478c2ecf20Sopenharmony_cistatic inline int l2cap_ecred_conn_rsp(struct l2cap_conn *conn,
61488c2ecf20Sopenharmony_ci				       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
61498c2ecf20Sopenharmony_ci				       u8 *data)
61508c2ecf20Sopenharmony_ci{
61518c2ecf20Sopenharmony_ci	struct l2cap_ecred_conn_rsp *rsp = (void *) data;
61528c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
61538c2ecf20Sopenharmony_ci	u16 mtu, mps, credits, result;
61548c2ecf20Sopenharmony_ci	struct l2cap_chan *chan, *tmp;
61558c2ecf20Sopenharmony_ci	int err = 0, sec_level;
61568c2ecf20Sopenharmony_ci	int i = 0;
61578c2ecf20Sopenharmony_ci
61588c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*rsp))
61598c2ecf20Sopenharmony_ci		return -EPROTO;
61608c2ecf20Sopenharmony_ci
61618c2ecf20Sopenharmony_ci	mtu     = __le16_to_cpu(rsp->mtu);
61628c2ecf20Sopenharmony_ci	mps     = __le16_to_cpu(rsp->mps);
61638c2ecf20Sopenharmony_ci	credits = __le16_to_cpu(rsp->credits);
61648c2ecf20Sopenharmony_ci	result  = __le16_to_cpu(rsp->result);
61658c2ecf20Sopenharmony_ci
61668c2ecf20Sopenharmony_ci	BT_DBG("mtu %u mps %u credits %u result 0x%4.4x", mtu, mps, credits,
61678c2ecf20Sopenharmony_ci	       result);
61688c2ecf20Sopenharmony_ci
61698c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
61708c2ecf20Sopenharmony_ci
61718c2ecf20Sopenharmony_ci	cmd_len -= sizeof(*rsp);
61728c2ecf20Sopenharmony_ci
61738c2ecf20Sopenharmony_ci	list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
61748c2ecf20Sopenharmony_ci		u16 dcid;
61758c2ecf20Sopenharmony_ci
61768c2ecf20Sopenharmony_ci		if (chan->ident != cmd->ident ||
61778c2ecf20Sopenharmony_ci		    chan->mode != L2CAP_MODE_EXT_FLOWCTL ||
61788c2ecf20Sopenharmony_ci		    chan->state == BT_CONNECTED)
61798c2ecf20Sopenharmony_ci			continue;
61808c2ecf20Sopenharmony_ci
61818c2ecf20Sopenharmony_ci		l2cap_chan_lock(chan);
61828c2ecf20Sopenharmony_ci
61838c2ecf20Sopenharmony_ci		/* Check that there is a dcid for each pending channel */
61848c2ecf20Sopenharmony_ci		if (cmd_len < sizeof(dcid)) {
61858c2ecf20Sopenharmony_ci			l2cap_chan_del(chan, ECONNREFUSED);
61868c2ecf20Sopenharmony_ci			l2cap_chan_unlock(chan);
61878c2ecf20Sopenharmony_ci			continue;
61888c2ecf20Sopenharmony_ci		}
61898c2ecf20Sopenharmony_ci
61908c2ecf20Sopenharmony_ci		dcid = __le16_to_cpu(rsp->dcid[i++]);
61918c2ecf20Sopenharmony_ci		cmd_len -= sizeof(u16);
61928c2ecf20Sopenharmony_ci
61938c2ecf20Sopenharmony_ci		BT_DBG("dcid[%d] 0x%4.4x", i, dcid);
61948c2ecf20Sopenharmony_ci
61958c2ecf20Sopenharmony_ci		/* Check if dcid is already in use */
61968c2ecf20Sopenharmony_ci		if (dcid && __l2cap_get_chan_by_dcid(conn, dcid)) {
61978c2ecf20Sopenharmony_ci			/* If a device receives a
61988c2ecf20Sopenharmony_ci			 * L2CAP_CREDIT_BASED_CONNECTION_RSP packet with an
61998c2ecf20Sopenharmony_ci			 * already-assigned Destination CID, then both the
62008c2ecf20Sopenharmony_ci			 * original channel and the new channel shall be
62018c2ecf20Sopenharmony_ci			 * immediately discarded and not used.
62028c2ecf20Sopenharmony_ci			 */
62038c2ecf20Sopenharmony_ci			l2cap_chan_del(chan, ECONNREFUSED);
62048c2ecf20Sopenharmony_ci			l2cap_chan_unlock(chan);
62058c2ecf20Sopenharmony_ci			chan = __l2cap_get_chan_by_dcid(conn, dcid);
62068c2ecf20Sopenharmony_ci			l2cap_chan_lock(chan);
62078c2ecf20Sopenharmony_ci			l2cap_chan_del(chan, ECONNRESET);
62088c2ecf20Sopenharmony_ci			l2cap_chan_unlock(chan);
62098c2ecf20Sopenharmony_ci			continue;
62108c2ecf20Sopenharmony_ci		}
62118c2ecf20Sopenharmony_ci
62128c2ecf20Sopenharmony_ci		switch (result) {
62138c2ecf20Sopenharmony_ci		case L2CAP_CR_LE_AUTHENTICATION:
62148c2ecf20Sopenharmony_ci		case L2CAP_CR_LE_ENCRYPTION:
62158c2ecf20Sopenharmony_ci			/* If we already have MITM protection we can't do
62168c2ecf20Sopenharmony_ci			 * anything.
62178c2ecf20Sopenharmony_ci			 */
62188c2ecf20Sopenharmony_ci			if (hcon->sec_level > BT_SECURITY_MEDIUM) {
62198c2ecf20Sopenharmony_ci				l2cap_chan_del(chan, ECONNREFUSED);
62208c2ecf20Sopenharmony_ci				break;
62218c2ecf20Sopenharmony_ci			}
62228c2ecf20Sopenharmony_ci
62238c2ecf20Sopenharmony_ci			sec_level = hcon->sec_level + 1;
62248c2ecf20Sopenharmony_ci			if (chan->sec_level < sec_level)
62258c2ecf20Sopenharmony_ci				chan->sec_level = sec_level;
62268c2ecf20Sopenharmony_ci
62278c2ecf20Sopenharmony_ci			/* We'll need to send a new Connect Request */
62288c2ecf20Sopenharmony_ci			clear_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags);
62298c2ecf20Sopenharmony_ci
62308c2ecf20Sopenharmony_ci			smp_conn_security(hcon, chan->sec_level);
62318c2ecf20Sopenharmony_ci			break;
62328c2ecf20Sopenharmony_ci
62338c2ecf20Sopenharmony_ci		case L2CAP_CR_LE_BAD_PSM:
62348c2ecf20Sopenharmony_ci			l2cap_chan_del(chan, ECONNREFUSED);
62358c2ecf20Sopenharmony_ci			break;
62368c2ecf20Sopenharmony_ci
62378c2ecf20Sopenharmony_ci		default:
62388c2ecf20Sopenharmony_ci			/* If dcid was not set it means channels was refused */
62398c2ecf20Sopenharmony_ci			if (!dcid) {
62408c2ecf20Sopenharmony_ci				l2cap_chan_del(chan, ECONNREFUSED);
62418c2ecf20Sopenharmony_ci				break;
62428c2ecf20Sopenharmony_ci			}
62438c2ecf20Sopenharmony_ci
62448c2ecf20Sopenharmony_ci			chan->ident = 0;
62458c2ecf20Sopenharmony_ci			chan->dcid = dcid;
62468c2ecf20Sopenharmony_ci			chan->omtu = mtu;
62478c2ecf20Sopenharmony_ci			chan->remote_mps = mps;
62488c2ecf20Sopenharmony_ci			chan->tx_credits = credits;
62498c2ecf20Sopenharmony_ci			l2cap_chan_ready(chan);
62508c2ecf20Sopenharmony_ci			break;
62518c2ecf20Sopenharmony_ci		}
62528c2ecf20Sopenharmony_ci
62538c2ecf20Sopenharmony_ci		l2cap_chan_unlock(chan);
62548c2ecf20Sopenharmony_ci	}
62558c2ecf20Sopenharmony_ci
62568c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
62578c2ecf20Sopenharmony_ci
62588c2ecf20Sopenharmony_ci	return err;
62598c2ecf20Sopenharmony_ci}
62608c2ecf20Sopenharmony_ci
62618c2ecf20Sopenharmony_cistatic inline int l2cap_ecred_reconf_req(struct l2cap_conn *conn,
62628c2ecf20Sopenharmony_ci					 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
62638c2ecf20Sopenharmony_ci					 u8 *data)
62648c2ecf20Sopenharmony_ci{
62658c2ecf20Sopenharmony_ci	struct l2cap_ecred_reconf_req *req = (void *) data;
62668c2ecf20Sopenharmony_ci	struct l2cap_ecred_reconf_rsp rsp;
62678c2ecf20Sopenharmony_ci	u16 mtu, mps, result;
62688c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
62698c2ecf20Sopenharmony_ci	int i, num_scid;
62708c2ecf20Sopenharmony_ci
62718c2ecf20Sopenharmony_ci	if (!enable_ecred)
62728c2ecf20Sopenharmony_ci		return -EINVAL;
62738c2ecf20Sopenharmony_ci
62748c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*req) || cmd_len - sizeof(*req) % sizeof(u16)) {
62758c2ecf20Sopenharmony_ci		result = L2CAP_CR_LE_INVALID_PARAMS;
62768c2ecf20Sopenharmony_ci		goto respond;
62778c2ecf20Sopenharmony_ci	}
62788c2ecf20Sopenharmony_ci
62798c2ecf20Sopenharmony_ci	mtu = __le16_to_cpu(req->mtu);
62808c2ecf20Sopenharmony_ci	mps = __le16_to_cpu(req->mps);
62818c2ecf20Sopenharmony_ci
62828c2ecf20Sopenharmony_ci	BT_DBG("mtu %u mps %u", mtu, mps);
62838c2ecf20Sopenharmony_ci
62848c2ecf20Sopenharmony_ci	if (mtu < L2CAP_ECRED_MIN_MTU) {
62858c2ecf20Sopenharmony_ci		result = L2CAP_RECONF_INVALID_MTU;
62868c2ecf20Sopenharmony_ci		goto respond;
62878c2ecf20Sopenharmony_ci	}
62888c2ecf20Sopenharmony_ci
62898c2ecf20Sopenharmony_ci	if (mps < L2CAP_ECRED_MIN_MPS) {
62908c2ecf20Sopenharmony_ci		result = L2CAP_RECONF_INVALID_MPS;
62918c2ecf20Sopenharmony_ci		goto respond;
62928c2ecf20Sopenharmony_ci	}
62938c2ecf20Sopenharmony_ci
62948c2ecf20Sopenharmony_ci	cmd_len -= sizeof(*req);
62958c2ecf20Sopenharmony_ci	num_scid = cmd_len / sizeof(u16);
62968c2ecf20Sopenharmony_ci	result = L2CAP_RECONF_SUCCESS;
62978c2ecf20Sopenharmony_ci
62988c2ecf20Sopenharmony_ci	for (i = 0; i < num_scid; i++) {
62998c2ecf20Sopenharmony_ci		u16 scid;
63008c2ecf20Sopenharmony_ci
63018c2ecf20Sopenharmony_ci		scid = __le16_to_cpu(req->scid[i]);
63028c2ecf20Sopenharmony_ci		if (!scid)
63038c2ecf20Sopenharmony_ci			return -EPROTO;
63048c2ecf20Sopenharmony_ci
63058c2ecf20Sopenharmony_ci		chan = __l2cap_get_chan_by_dcid(conn, scid);
63068c2ecf20Sopenharmony_ci		if (!chan)
63078c2ecf20Sopenharmony_ci			continue;
63088c2ecf20Sopenharmony_ci
63098c2ecf20Sopenharmony_ci		/* If the MTU value is decreased for any of the included
63108c2ecf20Sopenharmony_ci		 * channels, then the receiver shall disconnect all
63118c2ecf20Sopenharmony_ci		 * included channels.
63128c2ecf20Sopenharmony_ci		 */
63138c2ecf20Sopenharmony_ci		if (chan->omtu > mtu) {
63148c2ecf20Sopenharmony_ci			BT_ERR("chan %p decreased MTU %u -> %u", chan,
63158c2ecf20Sopenharmony_ci			       chan->omtu, mtu);
63168c2ecf20Sopenharmony_ci			result = L2CAP_RECONF_INVALID_MTU;
63178c2ecf20Sopenharmony_ci		}
63188c2ecf20Sopenharmony_ci
63198c2ecf20Sopenharmony_ci		chan->omtu = mtu;
63208c2ecf20Sopenharmony_ci		chan->remote_mps = mps;
63218c2ecf20Sopenharmony_ci	}
63228c2ecf20Sopenharmony_ci
63238c2ecf20Sopenharmony_cirespond:
63248c2ecf20Sopenharmony_ci	rsp.result = cpu_to_le16(result);
63258c2ecf20Sopenharmony_ci
63268c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, cmd->ident, L2CAP_ECRED_RECONF_RSP, sizeof(rsp),
63278c2ecf20Sopenharmony_ci		       &rsp);
63288c2ecf20Sopenharmony_ci
63298c2ecf20Sopenharmony_ci	return 0;
63308c2ecf20Sopenharmony_ci}
63318c2ecf20Sopenharmony_ci
63328c2ecf20Sopenharmony_cistatic inline int l2cap_ecred_reconf_rsp(struct l2cap_conn *conn,
63338c2ecf20Sopenharmony_ci					 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
63348c2ecf20Sopenharmony_ci					 u8 *data)
63358c2ecf20Sopenharmony_ci{
63368c2ecf20Sopenharmony_ci	struct l2cap_chan *chan, *tmp;
63378c2ecf20Sopenharmony_ci	struct l2cap_ecred_conn_rsp *rsp = (void *) data;
63388c2ecf20Sopenharmony_ci	u16 result;
63398c2ecf20Sopenharmony_ci
63408c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*rsp))
63418c2ecf20Sopenharmony_ci		return -EPROTO;
63428c2ecf20Sopenharmony_ci
63438c2ecf20Sopenharmony_ci	result = __le16_to_cpu(rsp->result);
63448c2ecf20Sopenharmony_ci
63458c2ecf20Sopenharmony_ci	BT_DBG("result 0x%4.4x", rsp->result);
63468c2ecf20Sopenharmony_ci
63478c2ecf20Sopenharmony_ci	if (!result)
63488c2ecf20Sopenharmony_ci		return 0;
63498c2ecf20Sopenharmony_ci
63508c2ecf20Sopenharmony_ci	list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
63518c2ecf20Sopenharmony_ci		if (chan->ident != cmd->ident)
63528c2ecf20Sopenharmony_ci			continue;
63538c2ecf20Sopenharmony_ci
63548c2ecf20Sopenharmony_ci		l2cap_chan_del(chan, ECONNRESET);
63558c2ecf20Sopenharmony_ci	}
63568c2ecf20Sopenharmony_ci
63578c2ecf20Sopenharmony_ci	return 0;
63588c2ecf20Sopenharmony_ci}
63598c2ecf20Sopenharmony_ci
63608c2ecf20Sopenharmony_cistatic inline int l2cap_le_command_rej(struct l2cap_conn *conn,
63618c2ecf20Sopenharmony_ci				       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
63628c2ecf20Sopenharmony_ci				       u8 *data)
63638c2ecf20Sopenharmony_ci{
63648c2ecf20Sopenharmony_ci	struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
63658c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
63668c2ecf20Sopenharmony_ci
63678c2ecf20Sopenharmony_ci	if (cmd_len < sizeof(*rej))
63688c2ecf20Sopenharmony_ci		return -EPROTO;
63698c2ecf20Sopenharmony_ci
63708c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
63718c2ecf20Sopenharmony_ci
63728c2ecf20Sopenharmony_ci	chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
63738c2ecf20Sopenharmony_ci	if (!chan)
63748c2ecf20Sopenharmony_ci		goto done;
63758c2ecf20Sopenharmony_ci
63768c2ecf20Sopenharmony_ci	chan = l2cap_chan_hold_unless_zero(chan);
63778c2ecf20Sopenharmony_ci	if (!chan)
63788c2ecf20Sopenharmony_ci		goto done;
63798c2ecf20Sopenharmony_ci
63808c2ecf20Sopenharmony_ci	l2cap_chan_lock(chan);
63818c2ecf20Sopenharmony_ci	l2cap_chan_del(chan, ECONNREFUSED);
63828c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
63838c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
63848c2ecf20Sopenharmony_ci
63858c2ecf20Sopenharmony_cidone:
63868c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
63878c2ecf20Sopenharmony_ci	return 0;
63888c2ecf20Sopenharmony_ci}
63898c2ecf20Sopenharmony_ci
63908c2ecf20Sopenharmony_cistatic inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
63918c2ecf20Sopenharmony_ci				   struct l2cap_cmd_hdr *cmd, u16 cmd_len,
63928c2ecf20Sopenharmony_ci				   u8 *data)
63938c2ecf20Sopenharmony_ci{
63948c2ecf20Sopenharmony_ci	int err = 0;
63958c2ecf20Sopenharmony_ci
63968c2ecf20Sopenharmony_ci	switch (cmd->code) {
63978c2ecf20Sopenharmony_ci	case L2CAP_COMMAND_REJ:
63988c2ecf20Sopenharmony_ci		l2cap_le_command_rej(conn, cmd, cmd_len, data);
63998c2ecf20Sopenharmony_ci		break;
64008c2ecf20Sopenharmony_ci
64018c2ecf20Sopenharmony_ci	case L2CAP_CONN_PARAM_UPDATE_REQ:
64028c2ecf20Sopenharmony_ci		err = l2cap_conn_param_update_req(conn, cmd, cmd_len, data);
64038c2ecf20Sopenharmony_ci		break;
64048c2ecf20Sopenharmony_ci
64058c2ecf20Sopenharmony_ci	case L2CAP_CONN_PARAM_UPDATE_RSP:
64068c2ecf20Sopenharmony_ci		break;
64078c2ecf20Sopenharmony_ci
64088c2ecf20Sopenharmony_ci	case L2CAP_LE_CONN_RSP:
64098c2ecf20Sopenharmony_ci		l2cap_le_connect_rsp(conn, cmd, cmd_len, data);
64108c2ecf20Sopenharmony_ci		break;
64118c2ecf20Sopenharmony_ci
64128c2ecf20Sopenharmony_ci	case L2CAP_LE_CONN_REQ:
64138c2ecf20Sopenharmony_ci		err = l2cap_le_connect_req(conn, cmd, cmd_len, data);
64148c2ecf20Sopenharmony_ci		break;
64158c2ecf20Sopenharmony_ci
64168c2ecf20Sopenharmony_ci	case L2CAP_LE_CREDITS:
64178c2ecf20Sopenharmony_ci		err = l2cap_le_credits(conn, cmd, cmd_len, data);
64188c2ecf20Sopenharmony_ci		break;
64198c2ecf20Sopenharmony_ci
64208c2ecf20Sopenharmony_ci	case L2CAP_ECRED_CONN_REQ:
64218c2ecf20Sopenharmony_ci		err = l2cap_ecred_conn_req(conn, cmd, cmd_len, data);
64228c2ecf20Sopenharmony_ci		break;
64238c2ecf20Sopenharmony_ci
64248c2ecf20Sopenharmony_ci	case L2CAP_ECRED_CONN_RSP:
64258c2ecf20Sopenharmony_ci		err = l2cap_ecred_conn_rsp(conn, cmd, cmd_len, data);
64268c2ecf20Sopenharmony_ci		break;
64278c2ecf20Sopenharmony_ci
64288c2ecf20Sopenharmony_ci	case L2CAP_ECRED_RECONF_REQ:
64298c2ecf20Sopenharmony_ci		err = l2cap_ecred_reconf_req(conn, cmd, cmd_len, data);
64308c2ecf20Sopenharmony_ci		break;
64318c2ecf20Sopenharmony_ci
64328c2ecf20Sopenharmony_ci	case L2CAP_ECRED_RECONF_RSP:
64338c2ecf20Sopenharmony_ci		err = l2cap_ecred_reconf_rsp(conn, cmd, cmd_len, data);
64348c2ecf20Sopenharmony_ci		break;
64358c2ecf20Sopenharmony_ci
64368c2ecf20Sopenharmony_ci	case L2CAP_DISCONN_REQ:
64378c2ecf20Sopenharmony_ci		err = l2cap_disconnect_req(conn, cmd, cmd_len, data);
64388c2ecf20Sopenharmony_ci		break;
64398c2ecf20Sopenharmony_ci
64408c2ecf20Sopenharmony_ci	case L2CAP_DISCONN_RSP:
64418c2ecf20Sopenharmony_ci		l2cap_disconnect_rsp(conn, cmd, cmd_len, data);
64428c2ecf20Sopenharmony_ci		break;
64438c2ecf20Sopenharmony_ci
64448c2ecf20Sopenharmony_ci	default:
64458c2ecf20Sopenharmony_ci		BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
64468c2ecf20Sopenharmony_ci		err = -EINVAL;
64478c2ecf20Sopenharmony_ci		break;
64488c2ecf20Sopenharmony_ci	}
64498c2ecf20Sopenharmony_ci
64508c2ecf20Sopenharmony_ci	return err;
64518c2ecf20Sopenharmony_ci}
64528c2ecf20Sopenharmony_ci
64538c2ecf20Sopenharmony_cistatic inline void l2cap_le_sig_channel(struct l2cap_conn *conn,
64548c2ecf20Sopenharmony_ci					struct sk_buff *skb)
64558c2ecf20Sopenharmony_ci{
64568c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
64578c2ecf20Sopenharmony_ci	struct l2cap_cmd_hdr *cmd;
64588c2ecf20Sopenharmony_ci	u16 len;
64598c2ecf20Sopenharmony_ci	int err;
64608c2ecf20Sopenharmony_ci
64618c2ecf20Sopenharmony_ci	if (hcon->type != LE_LINK)
64628c2ecf20Sopenharmony_ci		goto drop;
64638c2ecf20Sopenharmony_ci
64648c2ecf20Sopenharmony_ci	if (skb->len < L2CAP_CMD_HDR_SIZE)
64658c2ecf20Sopenharmony_ci		goto drop;
64668c2ecf20Sopenharmony_ci
64678c2ecf20Sopenharmony_ci	cmd = (void *) skb->data;
64688c2ecf20Sopenharmony_ci	skb_pull(skb, L2CAP_CMD_HDR_SIZE);
64698c2ecf20Sopenharmony_ci
64708c2ecf20Sopenharmony_ci	len = le16_to_cpu(cmd->len);
64718c2ecf20Sopenharmony_ci
64728c2ecf20Sopenharmony_ci	BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd->code, len, cmd->ident);
64738c2ecf20Sopenharmony_ci
64748c2ecf20Sopenharmony_ci	if (len != skb->len || !cmd->ident) {
64758c2ecf20Sopenharmony_ci		BT_DBG("corrupted command");
64768c2ecf20Sopenharmony_ci		goto drop;
64778c2ecf20Sopenharmony_ci	}
64788c2ecf20Sopenharmony_ci
64798c2ecf20Sopenharmony_ci	err = l2cap_le_sig_cmd(conn, cmd, len, skb->data);
64808c2ecf20Sopenharmony_ci	if (err) {
64818c2ecf20Sopenharmony_ci		struct l2cap_cmd_rej_unk rej;
64828c2ecf20Sopenharmony_ci
64838c2ecf20Sopenharmony_ci		BT_ERR("Wrong link type (%d)", err);
64848c2ecf20Sopenharmony_ci
64858c2ecf20Sopenharmony_ci		rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
64868c2ecf20Sopenharmony_ci		l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
64878c2ecf20Sopenharmony_ci			       sizeof(rej), &rej);
64888c2ecf20Sopenharmony_ci	}
64898c2ecf20Sopenharmony_ci
64908c2ecf20Sopenharmony_cidrop:
64918c2ecf20Sopenharmony_ci	kfree_skb(skb);
64928c2ecf20Sopenharmony_ci}
64938c2ecf20Sopenharmony_ci
64948c2ecf20Sopenharmony_cistatic inline void l2cap_sig_send_rej(struct l2cap_conn *conn, u16 ident)
64958c2ecf20Sopenharmony_ci{
64968c2ecf20Sopenharmony_ci	struct l2cap_cmd_rej_unk rej;
64978c2ecf20Sopenharmony_ci
64988c2ecf20Sopenharmony_ci	rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
64998c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
65008c2ecf20Sopenharmony_ci}
65018c2ecf20Sopenharmony_ci
65028c2ecf20Sopenharmony_cistatic inline void l2cap_sig_channel(struct l2cap_conn *conn,
65038c2ecf20Sopenharmony_ci				     struct sk_buff *skb)
65048c2ecf20Sopenharmony_ci{
65058c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
65068c2ecf20Sopenharmony_ci	struct l2cap_cmd_hdr *cmd;
65078c2ecf20Sopenharmony_ci	int err;
65088c2ecf20Sopenharmony_ci
65098c2ecf20Sopenharmony_ci	l2cap_raw_recv(conn, skb);
65108c2ecf20Sopenharmony_ci
65118c2ecf20Sopenharmony_ci	if (hcon->type != ACL_LINK)
65128c2ecf20Sopenharmony_ci		goto drop;
65138c2ecf20Sopenharmony_ci
65148c2ecf20Sopenharmony_ci	while (skb->len >= L2CAP_CMD_HDR_SIZE) {
65158c2ecf20Sopenharmony_ci		u16 len;
65168c2ecf20Sopenharmony_ci
65178c2ecf20Sopenharmony_ci		cmd = (void *) skb->data;
65188c2ecf20Sopenharmony_ci		skb_pull(skb, L2CAP_CMD_HDR_SIZE);
65198c2ecf20Sopenharmony_ci
65208c2ecf20Sopenharmony_ci		len = le16_to_cpu(cmd->len);
65218c2ecf20Sopenharmony_ci
65228c2ecf20Sopenharmony_ci		BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd->code, len,
65238c2ecf20Sopenharmony_ci		       cmd->ident);
65248c2ecf20Sopenharmony_ci
65258c2ecf20Sopenharmony_ci		if (len > skb->len || !cmd->ident) {
65268c2ecf20Sopenharmony_ci			BT_DBG("corrupted command");
65278c2ecf20Sopenharmony_ci			l2cap_sig_send_rej(conn, cmd->ident);
65288c2ecf20Sopenharmony_ci			skb_pull(skb, len > skb->len ? skb->len : len);
65298c2ecf20Sopenharmony_ci			continue;
65308c2ecf20Sopenharmony_ci		}
65318c2ecf20Sopenharmony_ci
65328c2ecf20Sopenharmony_ci		err = l2cap_bredr_sig_cmd(conn, cmd, len, skb->data);
65338c2ecf20Sopenharmony_ci		if (err) {
65348c2ecf20Sopenharmony_ci			BT_ERR("Wrong link type (%d)", err);
65358c2ecf20Sopenharmony_ci			l2cap_sig_send_rej(conn, cmd->ident);
65368c2ecf20Sopenharmony_ci		}
65378c2ecf20Sopenharmony_ci
65388c2ecf20Sopenharmony_ci		skb_pull(skb, len);
65398c2ecf20Sopenharmony_ci	}
65408c2ecf20Sopenharmony_ci
65418c2ecf20Sopenharmony_ci	if (skb->len > 0) {
65428c2ecf20Sopenharmony_ci		BT_DBG("corrupted command");
65438c2ecf20Sopenharmony_ci		l2cap_sig_send_rej(conn, 0);
65448c2ecf20Sopenharmony_ci	}
65458c2ecf20Sopenharmony_ci
65468c2ecf20Sopenharmony_cidrop:
65478c2ecf20Sopenharmony_ci	kfree_skb(skb);
65488c2ecf20Sopenharmony_ci}
65498c2ecf20Sopenharmony_ci
65508c2ecf20Sopenharmony_cistatic int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
65518c2ecf20Sopenharmony_ci{
65528c2ecf20Sopenharmony_ci	u16 our_fcs, rcv_fcs;
65538c2ecf20Sopenharmony_ci	int hdr_size;
65548c2ecf20Sopenharmony_ci
65558c2ecf20Sopenharmony_ci	if (test_bit(FLAG_EXT_CTRL, &chan->flags))
65568c2ecf20Sopenharmony_ci		hdr_size = L2CAP_EXT_HDR_SIZE;
65578c2ecf20Sopenharmony_ci	else
65588c2ecf20Sopenharmony_ci		hdr_size = L2CAP_ENH_HDR_SIZE;
65598c2ecf20Sopenharmony_ci
65608c2ecf20Sopenharmony_ci	if (chan->fcs == L2CAP_FCS_CRC16) {
65618c2ecf20Sopenharmony_ci		skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
65628c2ecf20Sopenharmony_ci		rcv_fcs = get_unaligned_le16(skb->data + skb->len);
65638c2ecf20Sopenharmony_ci		our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
65648c2ecf20Sopenharmony_ci
65658c2ecf20Sopenharmony_ci		if (our_fcs != rcv_fcs)
65668c2ecf20Sopenharmony_ci			return -EBADMSG;
65678c2ecf20Sopenharmony_ci	}
65688c2ecf20Sopenharmony_ci	return 0;
65698c2ecf20Sopenharmony_ci}
65708c2ecf20Sopenharmony_ci
65718c2ecf20Sopenharmony_cistatic void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
65728c2ecf20Sopenharmony_ci{
65738c2ecf20Sopenharmony_ci	struct l2cap_ctrl control;
65748c2ecf20Sopenharmony_ci
65758c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
65768c2ecf20Sopenharmony_ci
65778c2ecf20Sopenharmony_ci	memset(&control, 0, sizeof(control));
65788c2ecf20Sopenharmony_ci	control.sframe = 1;
65798c2ecf20Sopenharmony_ci	control.final = 1;
65808c2ecf20Sopenharmony_ci	control.reqseq = chan->buffer_seq;
65818c2ecf20Sopenharmony_ci	set_bit(CONN_SEND_FBIT, &chan->conn_state);
65828c2ecf20Sopenharmony_ci
65838c2ecf20Sopenharmony_ci	if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
65848c2ecf20Sopenharmony_ci		control.super = L2CAP_SUPER_RNR;
65858c2ecf20Sopenharmony_ci		l2cap_send_sframe(chan, &control);
65868c2ecf20Sopenharmony_ci	}
65878c2ecf20Sopenharmony_ci
65888c2ecf20Sopenharmony_ci	if (test_and_clear_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
65898c2ecf20Sopenharmony_ci	    chan->unacked_frames > 0)
65908c2ecf20Sopenharmony_ci		__set_retrans_timer(chan);
65918c2ecf20Sopenharmony_ci
65928c2ecf20Sopenharmony_ci	/* Send pending iframes */
65938c2ecf20Sopenharmony_ci	l2cap_ertm_send(chan);
65948c2ecf20Sopenharmony_ci
65958c2ecf20Sopenharmony_ci	if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
65968c2ecf20Sopenharmony_ci	    test_bit(CONN_SEND_FBIT, &chan->conn_state)) {
65978c2ecf20Sopenharmony_ci		/* F-bit wasn't sent in an s-frame or i-frame yet, so
65988c2ecf20Sopenharmony_ci		 * send it now.
65998c2ecf20Sopenharmony_ci		 */
66008c2ecf20Sopenharmony_ci		control.super = L2CAP_SUPER_RR;
66018c2ecf20Sopenharmony_ci		l2cap_send_sframe(chan, &control);
66028c2ecf20Sopenharmony_ci	}
66038c2ecf20Sopenharmony_ci}
66048c2ecf20Sopenharmony_ci
66058c2ecf20Sopenharmony_cistatic void append_skb_frag(struct sk_buff *skb, struct sk_buff *new_frag,
66068c2ecf20Sopenharmony_ci			    struct sk_buff **last_frag)
66078c2ecf20Sopenharmony_ci{
66088c2ecf20Sopenharmony_ci	/* skb->len reflects data in skb as well as all fragments
66098c2ecf20Sopenharmony_ci	 * skb->data_len reflects only data in fragments
66108c2ecf20Sopenharmony_ci	 */
66118c2ecf20Sopenharmony_ci	if (!skb_has_frag_list(skb))
66128c2ecf20Sopenharmony_ci		skb_shinfo(skb)->frag_list = new_frag;
66138c2ecf20Sopenharmony_ci
66148c2ecf20Sopenharmony_ci	new_frag->next = NULL;
66158c2ecf20Sopenharmony_ci
66168c2ecf20Sopenharmony_ci	(*last_frag)->next = new_frag;
66178c2ecf20Sopenharmony_ci	*last_frag = new_frag;
66188c2ecf20Sopenharmony_ci
66198c2ecf20Sopenharmony_ci	skb->len += new_frag->len;
66208c2ecf20Sopenharmony_ci	skb->data_len += new_frag->len;
66218c2ecf20Sopenharmony_ci	skb->truesize += new_frag->truesize;
66228c2ecf20Sopenharmony_ci}
66238c2ecf20Sopenharmony_ci
66248c2ecf20Sopenharmony_cistatic int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb,
66258c2ecf20Sopenharmony_ci				struct l2cap_ctrl *control)
66268c2ecf20Sopenharmony_ci{
66278c2ecf20Sopenharmony_ci	int err = -EINVAL;
66288c2ecf20Sopenharmony_ci
66298c2ecf20Sopenharmony_ci	switch (control->sar) {
66308c2ecf20Sopenharmony_ci	case L2CAP_SAR_UNSEGMENTED:
66318c2ecf20Sopenharmony_ci		if (chan->sdu)
66328c2ecf20Sopenharmony_ci			break;
66338c2ecf20Sopenharmony_ci
66348c2ecf20Sopenharmony_ci		err = chan->ops->recv(chan, skb);
66358c2ecf20Sopenharmony_ci		break;
66368c2ecf20Sopenharmony_ci
66378c2ecf20Sopenharmony_ci	case L2CAP_SAR_START:
66388c2ecf20Sopenharmony_ci		if (chan->sdu)
66398c2ecf20Sopenharmony_ci			break;
66408c2ecf20Sopenharmony_ci
66418c2ecf20Sopenharmony_ci		if (!pskb_may_pull(skb, L2CAP_SDULEN_SIZE))
66428c2ecf20Sopenharmony_ci			break;
66438c2ecf20Sopenharmony_ci
66448c2ecf20Sopenharmony_ci		chan->sdu_len = get_unaligned_le16(skb->data);
66458c2ecf20Sopenharmony_ci		skb_pull(skb, L2CAP_SDULEN_SIZE);
66468c2ecf20Sopenharmony_ci
66478c2ecf20Sopenharmony_ci		if (chan->sdu_len > chan->imtu) {
66488c2ecf20Sopenharmony_ci			err = -EMSGSIZE;
66498c2ecf20Sopenharmony_ci			break;
66508c2ecf20Sopenharmony_ci		}
66518c2ecf20Sopenharmony_ci
66528c2ecf20Sopenharmony_ci		if (skb->len >= chan->sdu_len)
66538c2ecf20Sopenharmony_ci			break;
66548c2ecf20Sopenharmony_ci
66558c2ecf20Sopenharmony_ci		chan->sdu = skb;
66568c2ecf20Sopenharmony_ci		chan->sdu_last_frag = skb;
66578c2ecf20Sopenharmony_ci
66588c2ecf20Sopenharmony_ci		skb = NULL;
66598c2ecf20Sopenharmony_ci		err = 0;
66608c2ecf20Sopenharmony_ci		break;
66618c2ecf20Sopenharmony_ci
66628c2ecf20Sopenharmony_ci	case L2CAP_SAR_CONTINUE:
66638c2ecf20Sopenharmony_ci		if (!chan->sdu)
66648c2ecf20Sopenharmony_ci			break;
66658c2ecf20Sopenharmony_ci
66668c2ecf20Sopenharmony_ci		append_skb_frag(chan->sdu, skb,
66678c2ecf20Sopenharmony_ci				&chan->sdu_last_frag);
66688c2ecf20Sopenharmony_ci		skb = NULL;
66698c2ecf20Sopenharmony_ci
66708c2ecf20Sopenharmony_ci		if (chan->sdu->len >= chan->sdu_len)
66718c2ecf20Sopenharmony_ci			break;
66728c2ecf20Sopenharmony_ci
66738c2ecf20Sopenharmony_ci		err = 0;
66748c2ecf20Sopenharmony_ci		break;
66758c2ecf20Sopenharmony_ci
66768c2ecf20Sopenharmony_ci	case L2CAP_SAR_END:
66778c2ecf20Sopenharmony_ci		if (!chan->sdu)
66788c2ecf20Sopenharmony_ci			break;
66798c2ecf20Sopenharmony_ci
66808c2ecf20Sopenharmony_ci		append_skb_frag(chan->sdu, skb,
66818c2ecf20Sopenharmony_ci				&chan->sdu_last_frag);
66828c2ecf20Sopenharmony_ci		skb = NULL;
66838c2ecf20Sopenharmony_ci
66848c2ecf20Sopenharmony_ci		if (chan->sdu->len != chan->sdu_len)
66858c2ecf20Sopenharmony_ci			break;
66868c2ecf20Sopenharmony_ci
66878c2ecf20Sopenharmony_ci		err = chan->ops->recv(chan, chan->sdu);
66888c2ecf20Sopenharmony_ci
66898c2ecf20Sopenharmony_ci		if (!err) {
66908c2ecf20Sopenharmony_ci			/* Reassembly complete */
66918c2ecf20Sopenharmony_ci			chan->sdu = NULL;
66928c2ecf20Sopenharmony_ci			chan->sdu_last_frag = NULL;
66938c2ecf20Sopenharmony_ci			chan->sdu_len = 0;
66948c2ecf20Sopenharmony_ci		}
66958c2ecf20Sopenharmony_ci		break;
66968c2ecf20Sopenharmony_ci	}
66978c2ecf20Sopenharmony_ci
66988c2ecf20Sopenharmony_ci	if (err) {
66998c2ecf20Sopenharmony_ci		kfree_skb(skb);
67008c2ecf20Sopenharmony_ci		kfree_skb(chan->sdu);
67018c2ecf20Sopenharmony_ci		chan->sdu = NULL;
67028c2ecf20Sopenharmony_ci		chan->sdu_last_frag = NULL;
67038c2ecf20Sopenharmony_ci		chan->sdu_len = 0;
67048c2ecf20Sopenharmony_ci	}
67058c2ecf20Sopenharmony_ci
67068c2ecf20Sopenharmony_ci	return err;
67078c2ecf20Sopenharmony_ci}
67088c2ecf20Sopenharmony_ci
67098c2ecf20Sopenharmony_cistatic int l2cap_resegment(struct l2cap_chan *chan)
67108c2ecf20Sopenharmony_ci{
67118c2ecf20Sopenharmony_ci	/* Placeholder */
67128c2ecf20Sopenharmony_ci	return 0;
67138c2ecf20Sopenharmony_ci}
67148c2ecf20Sopenharmony_ci
67158c2ecf20Sopenharmony_civoid l2cap_chan_busy(struct l2cap_chan *chan, int busy)
67168c2ecf20Sopenharmony_ci{
67178c2ecf20Sopenharmony_ci	u8 event;
67188c2ecf20Sopenharmony_ci
67198c2ecf20Sopenharmony_ci	if (chan->mode != L2CAP_MODE_ERTM)
67208c2ecf20Sopenharmony_ci		return;
67218c2ecf20Sopenharmony_ci
67228c2ecf20Sopenharmony_ci	event = busy ? L2CAP_EV_LOCAL_BUSY_DETECTED : L2CAP_EV_LOCAL_BUSY_CLEAR;
67238c2ecf20Sopenharmony_ci	l2cap_tx(chan, NULL, NULL, event);
67248c2ecf20Sopenharmony_ci}
67258c2ecf20Sopenharmony_ci
67268c2ecf20Sopenharmony_cistatic int l2cap_rx_queued_iframes(struct l2cap_chan *chan)
67278c2ecf20Sopenharmony_ci{
67288c2ecf20Sopenharmony_ci	int err = 0;
67298c2ecf20Sopenharmony_ci	/* Pass sequential frames to l2cap_reassemble_sdu()
67308c2ecf20Sopenharmony_ci	 * until a gap is encountered.
67318c2ecf20Sopenharmony_ci	 */
67328c2ecf20Sopenharmony_ci
67338c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
67348c2ecf20Sopenharmony_ci
67358c2ecf20Sopenharmony_ci	while (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
67368c2ecf20Sopenharmony_ci		struct sk_buff *skb;
67378c2ecf20Sopenharmony_ci		BT_DBG("Searching for skb with txseq %d (queue len %d)",
67388c2ecf20Sopenharmony_ci		       chan->buffer_seq, skb_queue_len(&chan->srej_q));
67398c2ecf20Sopenharmony_ci
67408c2ecf20Sopenharmony_ci		skb = l2cap_ertm_seq_in_queue(&chan->srej_q, chan->buffer_seq);
67418c2ecf20Sopenharmony_ci
67428c2ecf20Sopenharmony_ci		if (!skb)
67438c2ecf20Sopenharmony_ci			break;
67448c2ecf20Sopenharmony_ci
67458c2ecf20Sopenharmony_ci		skb_unlink(skb, &chan->srej_q);
67468c2ecf20Sopenharmony_ci		chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
67478c2ecf20Sopenharmony_ci		err = l2cap_reassemble_sdu(chan, skb, &bt_cb(skb)->l2cap);
67488c2ecf20Sopenharmony_ci		if (err)
67498c2ecf20Sopenharmony_ci			break;
67508c2ecf20Sopenharmony_ci	}
67518c2ecf20Sopenharmony_ci
67528c2ecf20Sopenharmony_ci	if (skb_queue_empty(&chan->srej_q)) {
67538c2ecf20Sopenharmony_ci		chan->rx_state = L2CAP_RX_STATE_RECV;
67548c2ecf20Sopenharmony_ci		l2cap_send_ack(chan);
67558c2ecf20Sopenharmony_ci	}
67568c2ecf20Sopenharmony_ci
67578c2ecf20Sopenharmony_ci	return err;
67588c2ecf20Sopenharmony_ci}
67598c2ecf20Sopenharmony_ci
67608c2ecf20Sopenharmony_cistatic void l2cap_handle_srej(struct l2cap_chan *chan,
67618c2ecf20Sopenharmony_ci			      struct l2cap_ctrl *control)
67628c2ecf20Sopenharmony_ci{
67638c2ecf20Sopenharmony_ci	struct sk_buff *skb;
67648c2ecf20Sopenharmony_ci
67658c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p", chan, control);
67668c2ecf20Sopenharmony_ci
67678c2ecf20Sopenharmony_ci	if (control->reqseq == chan->next_tx_seq) {
67688c2ecf20Sopenharmony_ci		BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
67698c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
67708c2ecf20Sopenharmony_ci		return;
67718c2ecf20Sopenharmony_ci	}
67728c2ecf20Sopenharmony_ci
67738c2ecf20Sopenharmony_ci	skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq);
67748c2ecf20Sopenharmony_ci
67758c2ecf20Sopenharmony_ci	if (skb == NULL) {
67768c2ecf20Sopenharmony_ci		BT_DBG("Seq %d not available for retransmission",
67778c2ecf20Sopenharmony_ci		       control->reqseq);
67788c2ecf20Sopenharmony_ci		return;
67798c2ecf20Sopenharmony_ci	}
67808c2ecf20Sopenharmony_ci
67818c2ecf20Sopenharmony_ci	if (chan->max_tx != 0 && bt_cb(skb)->l2cap.retries >= chan->max_tx) {
67828c2ecf20Sopenharmony_ci		BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
67838c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
67848c2ecf20Sopenharmony_ci		return;
67858c2ecf20Sopenharmony_ci	}
67868c2ecf20Sopenharmony_ci
67878c2ecf20Sopenharmony_ci	clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
67888c2ecf20Sopenharmony_ci
67898c2ecf20Sopenharmony_ci	if (control->poll) {
67908c2ecf20Sopenharmony_ci		l2cap_pass_to_tx(chan, control);
67918c2ecf20Sopenharmony_ci
67928c2ecf20Sopenharmony_ci		set_bit(CONN_SEND_FBIT, &chan->conn_state);
67938c2ecf20Sopenharmony_ci		l2cap_retransmit(chan, control);
67948c2ecf20Sopenharmony_ci		l2cap_ertm_send(chan);
67958c2ecf20Sopenharmony_ci
67968c2ecf20Sopenharmony_ci		if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) {
67978c2ecf20Sopenharmony_ci			set_bit(CONN_SREJ_ACT, &chan->conn_state);
67988c2ecf20Sopenharmony_ci			chan->srej_save_reqseq = control->reqseq;
67998c2ecf20Sopenharmony_ci		}
68008c2ecf20Sopenharmony_ci	} else {
68018c2ecf20Sopenharmony_ci		l2cap_pass_to_tx_fbit(chan, control);
68028c2ecf20Sopenharmony_ci
68038c2ecf20Sopenharmony_ci		if (control->final) {
68048c2ecf20Sopenharmony_ci			if (chan->srej_save_reqseq != control->reqseq ||
68058c2ecf20Sopenharmony_ci			    !test_and_clear_bit(CONN_SREJ_ACT,
68068c2ecf20Sopenharmony_ci						&chan->conn_state))
68078c2ecf20Sopenharmony_ci				l2cap_retransmit(chan, control);
68088c2ecf20Sopenharmony_ci		} else {
68098c2ecf20Sopenharmony_ci			l2cap_retransmit(chan, control);
68108c2ecf20Sopenharmony_ci			if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) {
68118c2ecf20Sopenharmony_ci				set_bit(CONN_SREJ_ACT, &chan->conn_state);
68128c2ecf20Sopenharmony_ci				chan->srej_save_reqseq = control->reqseq;
68138c2ecf20Sopenharmony_ci			}
68148c2ecf20Sopenharmony_ci		}
68158c2ecf20Sopenharmony_ci	}
68168c2ecf20Sopenharmony_ci}
68178c2ecf20Sopenharmony_ci
68188c2ecf20Sopenharmony_cistatic void l2cap_handle_rej(struct l2cap_chan *chan,
68198c2ecf20Sopenharmony_ci			     struct l2cap_ctrl *control)
68208c2ecf20Sopenharmony_ci{
68218c2ecf20Sopenharmony_ci	struct sk_buff *skb;
68228c2ecf20Sopenharmony_ci
68238c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p", chan, control);
68248c2ecf20Sopenharmony_ci
68258c2ecf20Sopenharmony_ci	if (control->reqseq == chan->next_tx_seq) {
68268c2ecf20Sopenharmony_ci		BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq);
68278c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
68288c2ecf20Sopenharmony_ci		return;
68298c2ecf20Sopenharmony_ci	}
68308c2ecf20Sopenharmony_ci
68318c2ecf20Sopenharmony_ci	skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq);
68328c2ecf20Sopenharmony_ci
68338c2ecf20Sopenharmony_ci	if (chan->max_tx && skb &&
68348c2ecf20Sopenharmony_ci	    bt_cb(skb)->l2cap.retries >= chan->max_tx) {
68358c2ecf20Sopenharmony_ci		BT_DBG("Retry limit exceeded (%d)", chan->max_tx);
68368c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
68378c2ecf20Sopenharmony_ci		return;
68388c2ecf20Sopenharmony_ci	}
68398c2ecf20Sopenharmony_ci
68408c2ecf20Sopenharmony_ci	clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
68418c2ecf20Sopenharmony_ci
68428c2ecf20Sopenharmony_ci	l2cap_pass_to_tx(chan, control);
68438c2ecf20Sopenharmony_ci
68448c2ecf20Sopenharmony_ci	if (control->final) {
68458c2ecf20Sopenharmony_ci		if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
68468c2ecf20Sopenharmony_ci			l2cap_retransmit_all(chan, control);
68478c2ecf20Sopenharmony_ci	} else {
68488c2ecf20Sopenharmony_ci		l2cap_retransmit_all(chan, control);
68498c2ecf20Sopenharmony_ci		l2cap_ertm_send(chan);
68508c2ecf20Sopenharmony_ci		if (chan->tx_state == L2CAP_TX_STATE_WAIT_F)
68518c2ecf20Sopenharmony_ci			set_bit(CONN_REJ_ACT, &chan->conn_state);
68528c2ecf20Sopenharmony_ci	}
68538c2ecf20Sopenharmony_ci}
68548c2ecf20Sopenharmony_ci
68558c2ecf20Sopenharmony_cistatic u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq)
68568c2ecf20Sopenharmony_ci{
68578c2ecf20Sopenharmony_ci	BT_DBG("chan %p, txseq %d", chan, txseq);
68588c2ecf20Sopenharmony_ci
68598c2ecf20Sopenharmony_ci	BT_DBG("last_acked_seq %d, expected_tx_seq %d", chan->last_acked_seq,
68608c2ecf20Sopenharmony_ci	       chan->expected_tx_seq);
68618c2ecf20Sopenharmony_ci
68628c2ecf20Sopenharmony_ci	if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
68638c2ecf20Sopenharmony_ci		if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
68648c2ecf20Sopenharmony_ci		    chan->tx_win) {
68658c2ecf20Sopenharmony_ci			/* See notes below regarding "double poll" and
68668c2ecf20Sopenharmony_ci			 * invalid packets.
68678c2ecf20Sopenharmony_ci			 */
68688c2ecf20Sopenharmony_ci			if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) {
68698c2ecf20Sopenharmony_ci				BT_DBG("Invalid/Ignore - after SREJ");
68708c2ecf20Sopenharmony_ci				return L2CAP_TXSEQ_INVALID_IGNORE;
68718c2ecf20Sopenharmony_ci			} else {
68728c2ecf20Sopenharmony_ci				BT_DBG("Invalid - in window after SREJ sent");
68738c2ecf20Sopenharmony_ci				return L2CAP_TXSEQ_INVALID;
68748c2ecf20Sopenharmony_ci			}
68758c2ecf20Sopenharmony_ci		}
68768c2ecf20Sopenharmony_ci
68778c2ecf20Sopenharmony_ci		if (chan->srej_list.head == txseq) {
68788c2ecf20Sopenharmony_ci			BT_DBG("Expected SREJ");
68798c2ecf20Sopenharmony_ci			return L2CAP_TXSEQ_EXPECTED_SREJ;
68808c2ecf20Sopenharmony_ci		}
68818c2ecf20Sopenharmony_ci
68828c2ecf20Sopenharmony_ci		if (l2cap_ertm_seq_in_queue(&chan->srej_q, txseq)) {
68838c2ecf20Sopenharmony_ci			BT_DBG("Duplicate SREJ - txseq already stored");
68848c2ecf20Sopenharmony_ci			return L2CAP_TXSEQ_DUPLICATE_SREJ;
68858c2ecf20Sopenharmony_ci		}
68868c2ecf20Sopenharmony_ci
68878c2ecf20Sopenharmony_ci		if (l2cap_seq_list_contains(&chan->srej_list, txseq)) {
68888c2ecf20Sopenharmony_ci			BT_DBG("Unexpected SREJ - not requested");
68898c2ecf20Sopenharmony_ci			return L2CAP_TXSEQ_UNEXPECTED_SREJ;
68908c2ecf20Sopenharmony_ci		}
68918c2ecf20Sopenharmony_ci	}
68928c2ecf20Sopenharmony_ci
68938c2ecf20Sopenharmony_ci	if (chan->expected_tx_seq == txseq) {
68948c2ecf20Sopenharmony_ci		if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
68958c2ecf20Sopenharmony_ci		    chan->tx_win) {
68968c2ecf20Sopenharmony_ci			BT_DBG("Invalid - txseq outside tx window");
68978c2ecf20Sopenharmony_ci			return L2CAP_TXSEQ_INVALID;
68988c2ecf20Sopenharmony_ci		} else {
68998c2ecf20Sopenharmony_ci			BT_DBG("Expected");
69008c2ecf20Sopenharmony_ci			return L2CAP_TXSEQ_EXPECTED;
69018c2ecf20Sopenharmony_ci		}
69028c2ecf20Sopenharmony_ci	}
69038c2ecf20Sopenharmony_ci
69048c2ecf20Sopenharmony_ci	if (__seq_offset(chan, txseq, chan->last_acked_seq) <
69058c2ecf20Sopenharmony_ci	    __seq_offset(chan, chan->expected_tx_seq, chan->last_acked_seq)) {
69068c2ecf20Sopenharmony_ci		BT_DBG("Duplicate - expected_tx_seq later than txseq");
69078c2ecf20Sopenharmony_ci		return L2CAP_TXSEQ_DUPLICATE;
69088c2ecf20Sopenharmony_ci	}
69098c2ecf20Sopenharmony_ci
69108c2ecf20Sopenharmony_ci	if (__seq_offset(chan, txseq, chan->last_acked_seq) >= chan->tx_win) {
69118c2ecf20Sopenharmony_ci		/* A source of invalid packets is a "double poll" condition,
69128c2ecf20Sopenharmony_ci		 * where delays cause us to send multiple poll packets.  If
69138c2ecf20Sopenharmony_ci		 * the remote stack receives and processes both polls,
69148c2ecf20Sopenharmony_ci		 * sequence numbers can wrap around in such a way that a
69158c2ecf20Sopenharmony_ci		 * resent frame has a sequence number that looks like new data
69168c2ecf20Sopenharmony_ci		 * with a sequence gap.  This would trigger an erroneous SREJ
69178c2ecf20Sopenharmony_ci		 * request.
69188c2ecf20Sopenharmony_ci		 *
69198c2ecf20Sopenharmony_ci		 * Fortunately, this is impossible with a tx window that's
69208c2ecf20Sopenharmony_ci		 * less than half of the maximum sequence number, which allows
69218c2ecf20Sopenharmony_ci		 * invalid frames to be safely ignored.
69228c2ecf20Sopenharmony_ci		 *
69238c2ecf20Sopenharmony_ci		 * With tx window sizes greater than half of the tx window
69248c2ecf20Sopenharmony_ci		 * maximum, the frame is invalid and cannot be ignored.  This
69258c2ecf20Sopenharmony_ci		 * causes a disconnect.
69268c2ecf20Sopenharmony_ci		 */
69278c2ecf20Sopenharmony_ci
69288c2ecf20Sopenharmony_ci		if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) {
69298c2ecf20Sopenharmony_ci			BT_DBG("Invalid/Ignore - txseq outside tx window");
69308c2ecf20Sopenharmony_ci			return L2CAP_TXSEQ_INVALID_IGNORE;
69318c2ecf20Sopenharmony_ci		} else {
69328c2ecf20Sopenharmony_ci			BT_DBG("Invalid - txseq outside tx window");
69338c2ecf20Sopenharmony_ci			return L2CAP_TXSEQ_INVALID;
69348c2ecf20Sopenharmony_ci		}
69358c2ecf20Sopenharmony_ci	} else {
69368c2ecf20Sopenharmony_ci		BT_DBG("Unexpected - txseq indicates missing frames");
69378c2ecf20Sopenharmony_ci		return L2CAP_TXSEQ_UNEXPECTED;
69388c2ecf20Sopenharmony_ci	}
69398c2ecf20Sopenharmony_ci}
69408c2ecf20Sopenharmony_ci
69418c2ecf20Sopenharmony_cistatic int l2cap_rx_state_recv(struct l2cap_chan *chan,
69428c2ecf20Sopenharmony_ci			       struct l2cap_ctrl *control,
69438c2ecf20Sopenharmony_ci			       struct sk_buff *skb, u8 event)
69448c2ecf20Sopenharmony_ci{
69458c2ecf20Sopenharmony_ci	struct l2cap_ctrl local_control;
69468c2ecf20Sopenharmony_ci	int err = 0;
69478c2ecf20Sopenharmony_ci	bool skb_in_use = false;
69488c2ecf20Sopenharmony_ci
69498c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
69508c2ecf20Sopenharmony_ci	       event);
69518c2ecf20Sopenharmony_ci
69528c2ecf20Sopenharmony_ci	switch (event) {
69538c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_IFRAME:
69548c2ecf20Sopenharmony_ci		switch (l2cap_classify_txseq(chan, control->txseq)) {
69558c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_EXPECTED:
69568c2ecf20Sopenharmony_ci			l2cap_pass_to_tx(chan, control);
69578c2ecf20Sopenharmony_ci
69588c2ecf20Sopenharmony_ci			if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
69598c2ecf20Sopenharmony_ci				BT_DBG("Busy, discarding expected seq %d",
69608c2ecf20Sopenharmony_ci				       control->txseq);
69618c2ecf20Sopenharmony_ci				break;
69628c2ecf20Sopenharmony_ci			}
69638c2ecf20Sopenharmony_ci
69648c2ecf20Sopenharmony_ci			chan->expected_tx_seq = __next_seq(chan,
69658c2ecf20Sopenharmony_ci							   control->txseq);
69668c2ecf20Sopenharmony_ci
69678c2ecf20Sopenharmony_ci			chan->buffer_seq = chan->expected_tx_seq;
69688c2ecf20Sopenharmony_ci			skb_in_use = true;
69698c2ecf20Sopenharmony_ci
69708c2ecf20Sopenharmony_ci			/* l2cap_reassemble_sdu may free skb, hence invalidate
69718c2ecf20Sopenharmony_ci			 * control, so make a copy in advance to use it after
69728c2ecf20Sopenharmony_ci			 * l2cap_reassemble_sdu returns and to avoid the race
69738c2ecf20Sopenharmony_ci			 * condition, for example:
69748c2ecf20Sopenharmony_ci			 *
69758c2ecf20Sopenharmony_ci			 * The current thread calls:
69768c2ecf20Sopenharmony_ci			 *   l2cap_reassemble_sdu
69778c2ecf20Sopenharmony_ci			 *     chan->ops->recv == l2cap_sock_recv_cb
69788c2ecf20Sopenharmony_ci			 *       __sock_queue_rcv_skb
69798c2ecf20Sopenharmony_ci			 * Another thread calls:
69808c2ecf20Sopenharmony_ci			 *   bt_sock_recvmsg
69818c2ecf20Sopenharmony_ci			 *     skb_recv_datagram
69828c2ecf20Sopenharmony_ci			 *     skb_free_datagram
69838c2ecf20Sopenharmony_ci			 * Then the current thread tries to access control, but
69848c2ecf20Sopenharmony_ci			 * it was freed by skb_free_datagram.
69858c2ecf20Sopenharmony_ci			 */
69868c2ecf20Sopenharmony_ci			local_control = *control;
69878c2ecf20Sopenharmony_ci			err = l2cap_reassemble_sdu(chan, skb, control);
69888c2ecf20Sopenharmony_ci			if (err)
69898c2ecf20Sopenharmony_ci				break;
69908c2ecf20Sopenharmony_ci
69918c2ecf20Sopenharmony_ci			if (local_control.final) {
69928c2ecf20Sopenharmony_ci				if (!test_and_clear_bit(CONN_REJ_ACT,
69938c2ecf20Sopenharmony_ci							&chan->conn_state)) {
69948c2ecf20Sopenharmony_ci					local_control.final = 0;
69958c2ecf20Sopenharmony_ci					l2cap_retransmit_all(chan, &local_control);
69968c2ecf20Sopenharmony_ci					l2cap_ertm_send(chan);
69978c2ecf20Sopenharmony_ci				}
69988c2ecf20Sopenharmony_ci			}
69998c2ecf20Sopenharmony_ci
70008c2ecf20Sopenharmony_ci			if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
70018c2ecf20Sopenharmony_ci				l2cap_send_ack(chan);
70028c2ecf20Sopenharmony_ci			break;
70038c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_UNEXPECTED:
70048c2ecf20Sopenharmony_ci			l2cap_pass_to_tx(chan, control);
70058c2ecf20Sopenharmony_ci
70068c2ecf20Sopenharmony_ci			/* Can't issue SREJ frames in the local busy state.
70078c2ecf20Sopenharmony_ci			 * Drop this frame, it will be seen as missing
70088c2ecf20Sopenharmony_ci			 * when local busy is exited.
70098c2ecf20Sopenharmony_ci			 */
70108c2ecf20Sopenharmony_ci			if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
70118c2ecf20Sopenharmony_ci				BT_DBG("Busy, discarding unexpected seq %d",
70128c2ecf20Sopenharmony_ci				       control->txseq);
70138c2ecf20Sopenharmony_ci				break;
70148c2ecf20Sopenharmony_ci			}
70158c2ecf20Sopenharmony_ci
70168c2ecf20Sopenharmony_ci			/* There was a gap in the sequence, so an SREJ
70178c2ecf20Sopenharmony_ci			 * must be sent for each missing frame.  The
70188c2ecf20Sopenharmony_ci			 * current frame is stored for later use.
70198c2ecf20Sopenharmony_ci			 */
70208c2ecf20Sopenharmony_ci			skb_queue_tail(&chan->srej_q, skb);
70218c2ecf20Sopenharmony_ci			skb_in_use = true;
70228c2ecf20Sopenharmony_ci			BT_DBG("Queued %p (queue len %d)", skb,
70238c2ecf20Sopenharmony_ci			       skb_queue_len(&chan->srej_q));
70248c2ecf20Sopenharmony_ci
70258c2ecf20Sopenharmony_ci			clear_bit(CONN_SREJ_ACT, &chan->conn_state);
70268c2ecf20Sopenharmony_ci			l2cap_seq_list_clear(&chan->srej_list);
70278c2ecf20Sopenharmony_ci			l2cap_send_srej(chan, control->txseq);
70288c2ecf20Sopenharmony_ci
70298c2ecf20Sopenharmony_ci			chan->rx_state = L2CAP_RX_STATE_SREJ_SENT;
70308c2ecf20Sopenharmony_ci			break;
70318c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_DUPLICATE:
70328c2ecf20Sopenharmony_ci			l2cap_pass_to_tx(chan, control);
70338c2ecf20Sopenharmony_ci			break;
70348c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_INVALID_IGNORE:
70358c2ecf20Sopenharmony_ci			break;
70368c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_INVALID:
70378c2ecf20Sopenharmony_ci		default:
70388c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, ECONNRESET);
70398c2ecf20Sopenharmony_ci			break;
70408c2ecf20Sopenharmony_ci		}
70418c2ecf20Sopenharmony_ci		break;
70428c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_RR:
70438c2ecf20Sopenharmony_ci		l2cap_pass_to_tx(chan, control);
70448c2ecf20Sopenharmony_ci		if (control->final) {
70458c2ecf20Sopenharmony_ci			clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
70468c2ecf20Sopenharmony_ci
70478c2ecf20Sopenharmony_ci			if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state) &&
70488c2ecf20Sopenharmony_ci			    !__chan_is_moving(chan)) {
70498c2ecf20Sopenharmony_ci				control->final = 0;
70508c2ecf20Sopenharmony_ci				l2cap_retransmit_all(chan, control);
70518c2ecf20Sopenharmony_ci			}
70528c2ecf20Sopenharmony_ci
70538c2ecf20Sopenharmony_ci			l2cap_ertm_send(chan);
70548c2ecf20Sopenharmony_ci		} else if (control->poll) {
70558c2ecf20Sopenharmony_ci			l2cap_send_i_or_rr_or_rnr(chan);
70568c2ecf20Sopenharmony_ci		} else {
70578c2ecf20Sopenharmony_ci			if (test_and_clear_bit(CONN_REMOTE_BUSY,
70588c2ecf20Sopenharmony_ci					       &chan->conn_state) &&
70598c2ecf20Sopenharmony_ci			    chan->unacked_frames)
70608c2ecf20Sopenharmony_ci				__set_retrans_timer(chan);
70618c2ecf20Sopenharmony_ci
70628c2ecf20Sopenharmony_ci			l2cap_ertm_send(chan);
70638c2ecf20Sopenharmony_ci		}
70648c2ecf20Sopenharmony_ci		break;
70658c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_RNR:
70668c2ecf20Sopenharmony_ci		set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
70678c2ecf20Sopenharmony_ci		l2cap_pass_to_tx(chan, control);
70688c2ecf20Sopenharmony_ci		if (control && control->poll) {
70698c2ecf20Sopenharmony_ci			set_bit(CONN_SEND_FBIT, &chan->conn_state);
70708c2ecf20Sopenharmony_ci			l2cap_send_rr_or_rnr(chan, 0);
70718c2ecf20Sopenharmony_ci		}
70728c2ecf20Sopenharmony_ci		__clear_retrans_timer(chan);
70738c2ecf20Sopenharmony_ci		l2cap_seq_list_clear(&chan->retrans_list);
70748c2ecf20Sopenharmony_ci		break;
70758c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_REJ:
70768c2ecf20Sopenharmony_ci		l2cap_handle_rej(chan, control);
70778c2ecf20Sopenharmony_ci		break;
70788c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_SREJ:
70798c2ecf20Sopenharmony_ci		l2cap_handle_srej(chan, control);
70808c2ecf20Sopenharmony_ci		break;
70818c2ecf20Sopenharmony_ci	default:
70828c2ecf20Sopenharmony_ci		break;
70838c2ecf20Sopenharmony_ci	}
70848c2ecf20Sopenharmony_ci
70858c2ecf20Sopenharmony_ci	if (skb && !skb_in_use) {
70868c2ecf20Sopenharmony_ci		BT_DBG("Freeing %p", skb);
70878c2ecf20Sopenharmony_ci		kfree_skb(skb);
70888c2ecf20Sopenharmony_ci	}
70898c2ecf20Sopenharmony_ci
70908c2ecf20Sopenharmony_ci	return err;
70918c2ecf20Sopenharmony_ci}
70928c2ecf20Sopenharmony_ci
70938c2ecf20Sopenharmony_cistatic int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
70948c2ecf20Sopenharmony_ci				    struct l2cap_ctrl *control,
70958c2ecf20Sopenharmony_ci				    struct sk_buff *skb, u8 event)
70968c2ecf20Sopenharmony_ci{
70978c2ecf20Sopenharmony_ci	int err = 0;
70988c2ecf20Sopenharmony_ci	u16 txseq = control->txseq;
70998c2ecf20Sopenharmony_ci	bool skb_in_use = false;
71008c2ecf20Sopenharmony_ci
71018c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
71028c2ecf20Sopenharmony_ci	       event);
71038c2ecf20Sopenharmony_ci
71048c2ecf20Sopenharmony_ci	switch (event) {
71058c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_IFRAME:
71068c2ecf20Sopenharmony_ci		switch (l2cap_classify_txseq(chan, txseq)) {
71078c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_EXPECTED:
71088c2ecf20Sopenharmony_ci			/* Keep frame for reassembly later */
71098c2ecf20Sopenharmony_ci			l2cap_pass_to_tx(chan, control);
71108c2ecf20Sopenharmony_ci			skb_queue_tail(&chan->srej_q, skb);
71118c2ecf20Sopenharmony_ci			skb_in_use = true;
71128c2ecf20Sopenharmony_ci			BT_DBG("Queued %p (queue len %d)", skb,
71138c2ecf20Sopenharmony_ci			       skb_queue_len(&chan->srej_q));
71148c2ecf20Sopenharmony_ci
71158c2ecf20Sopenharmony_ci			chan->expected_tx_seq = __next_seq(chan, txseq);
71168c2ecf20Sopenharmony_ci			break;
71178c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_EXPECTED_SREJ:
71188c2ecf20Sopenharmony_ci			l2cap_seq_list_pop(&chan->srej_list);
71198c2ecf20Sopenharmony_ci
71208c2ecf20Sopenharmony_ci			l2cap_pass_to_tx(chan, control);
71218c2ecf20Sopenharmony_ci			skb_queue_tail(&chan->srej_q, skb);
71228c2ecf20Sopenharmony_ci			skb_in_use = true;
71238c2ecf20Sopenharmony_ci			BT_DBG("Queued %p (queue len %d)", skb,
71248c2ecf20Sopenharmony_ci			       skb_queue_len(&chan->srej_q));
71258c2ecf20Sopenharmony_ci
71268c2ecf20Sopenharmony_ci			err = l2cap_rx_queued_iframes(chan);
71278c2ecf20Sopenharmony_ci			if (err)
71288c2ecf20Sopenharmony_ci				break;
71298c2ecf20Sopenharmony_ci
71308c2ecf20Sopenharmony_ci			break;
71318c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_UNEXPECTED:
71328c2ecf20Sopenharmony_ci			/* Got a frame that can't be reassembled yet.
71338c2ecf20Sopenharmony_ci			 * Save it for later, and send SREJs to cover
71348c2ecf20Sopenharmony_ci			 * the missing frames.
71358c2ecf20Sopenharmony_ci			 */
71368c2ecf20Sopenharmony_ci			skb_queue_tail(&chan->srej_q, skb);
71378c2ecf20Sopenharmony_ci			skb_in_use = true;
71388c2ecf20Sopenharmony_ci			BT_DBG("Queued %p (queue len %d)", skb,
71398c2ecf20Sopenharmony_ci			       skb_queue_len(&chan->srej_q));
71408c2ecf20Sopenharmony_ci
71418c2ecf20Sopenharmony_ci			l2cap_pass_to_tx(chan, control);
71428c2ecf20Sopenharmony_ci			l2cap_send_srej(chan, control->txseq);
71438c2ecf20Sopenharmony_ci			break;
71448c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_UNEXPECTED_SREJ:
71458c2ecf20Sopenharmony_ci			/* This frame was requested with an SREJ, but
71468c2ecf20Sopenharmony_ci			 * some expected retransmitted frames are
71478c2ecf20Sopenharmony_ci			 * missing.  Request retransmission of missing
71488c2ecf20Sopenharmony_ci			 * SREJ'd frames.
71498c2ecf20Sopenharmony_ci			 */
71508c2ecf20Sopenharmony_ci			skb_queue_tail(&chan->srej_q, skb);
71518c2ecf20Sopenharmony_ci			skb_in_use = true;
71528c2ecf20Sopenharmony_ci			BT_DBG("Queued %p (queue len %d)", skb,
71538c2ecf20Sopenharmony_ci			       skb_queue_len(&chan->srej_q));
71548c2ecf20Sopenharmony_ci
71558c2ecf20Sopenharmony_ci			l2cap_pass_to_tx(chan, control);
71568c2ecf20Sopenharmony_ci			l2cap_send_srej_list(chan, control->txseq);
71578c2ecf20Sopenharmony_ci			break;
71588c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_DUPLICATE_SREJ:
71598c2ecf20Sopenharmony_ci			/* We've already queued this frame.  Drop this copy. */
71608c2ecf20Sopenharmony_ci			l2cap_pass_to_tx(chan, control);
71618c2ecf20Sopenharmony_ci			break;
71628c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_DUPLICATE:
71638c2ecf20Sopenharmony_ci			/* Expecting a later sequence number, so this frame
71648c2ecf20Sopenharmony_ci			 * was already received.  Ignore it completely.
71658c2ecf20Sopenharmony_ci			 */
71668c2ecf20Sopenharmony_ci			break;
71678c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_INVALID_IGNORE:
71688c2ecf20Sopenharmony_ci			break;
71698c2ecf20Sopenharmony_ci		case L2CAP_TXSEQ_INVALID:
71708c2ecf20Sopenharmony_ci		default:
71718c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, ECONNRESET);
71728c2ecf20Sopenharmony_ci			break;
71738c2ecf20Sopenharmony_ci		}
71748c2ecf20Sopenharmony_ci		break;
71758c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_RR:
71768c2ecf20Sopenharmony_ci		l2cap_pass_to_tx(chan, control);
71778c2ecf20Sopenharmony_ci		if (control->final) {
71788c2ecf20Sopenharmony_ci			clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
71798c2ecf20Sopenharmony_ci
71808c2ecf20Sopenharmony_ci			if (!test_and_clear_bit(CONN_REJ_ACT,
71818c2ecf20Sopenharmony_ci						&chan->conn_state)) {
71828c2ecf20Sopenharmony_ci				control->final = 0;
71838c2ecf20Sopenharmony_ci				l2cap_retransmit_all(chan, control);
71848c2ecf20Sopenharmony_ci			}
71858c2ecf20Sopenharmony_ci
71868c2ecf20Sopenharmony_ci			l2cap_ertm_send(chan);
71878c2ecf20Sopenharmony_ci		} else if (control->poll) {
71888c2ecf20Sopenharmony_ci			if (test_and_clear_bit(CONN_REMOTE_BUSY,
71898c2ecf20Sopenharmony_ci					       &chan->conn_state) &&
71908c2ecf20Sopenharmony_ci			    chan->unacked_frames) {
71918c2ecf20Sopenharmony_ci				__set_retrans_timer(chan);
71928c2ecf20Sopenharmony_ci			}
71938c2ecf20Sopenharmony_ci
71948c2ecf20Sopenharmony_ci			set_bit(CONN_SEND_FBIT, &chan->conn_state);
71958c2ecf20Sopenharmony_ci			l2cap_send_srej_tail(chan);
71968c2ecf20Sopenharmony_ci		} else {
71978c2ecf20Sopenharmony_ci			if (test_and_clear_bit(CONN_REMOTE_BUSY,
71988c2ecf20Sopenharmony_ci					       &chan->conn_state) &&
71998c2ecf20Sopenharmony_ci			    chan->unacked_frames)
72008c2ecf20Sopenharmony_ci				__set_retrans_timer(chan);
72018c2ecf20Sopenharmony_ci
72028c2ecf20Sopenharmony_ci			l2cap_send_ack(chan);
72038c2ecf20Sopenharmony_ci		}
72048c2ecf20Sopenharmony_ci		break;
72058c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_RNR:
72068c2ecf20Sopenharmony_ci		set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
72078c2ecf20Sopenharmony_ci		l2cap_pass_to_tx(chan, control);
72088c2ecf20Sopenharmony_ci		if (control->poll) {
72098c2ecf20Sopenharmony_ci			l2cap_send_srej_tail(chan);
72108c2ecf20Sopenharmony_ci		} else {
72118c2ecf20Sopenharmony_ci			struct l2cap_ctrl rr_control;
72128c2ecf20Sopenharmony_ci			memset(&rr_control, 0, sizeof(rr_control));
72138c2ecf20Sopenharmony_ci			rr_control.sframe = 1;
72148c2ecf20Sopenharmony_ci			rr_control.super = L2CAP_SUPER_RR;
72158c2ecf20Sopenharmony_ci			rr_control.reqseq = chan->buffer_seq;
72168c2ecf20Sopenharmony_ci			l2cap_send_sframe(chan, &rr_control);
72178c2ecf20Sopenharmony_ci		}
72188c2ecf20Sopenharmony_ci
72198c2ecf20Sopenharmony_ci		break;
72208c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_REJ:
72218c2ecf20Sopenharmony_ci		l2cap_handle_rej(chan, control);
72228c2ecf20Sopenharmony_ci		break;
72238c2ecf20Sopenharmony_ci	case L2CAP_EV_RECV_SREJ:
72248c2ecf20Sopenharmony_ci		l2cap_handle_srej(chan, control);
72258c2ecf20Sopenharmony_ci		break;
72268c2ecf20Sopenharmony_ci	}
72278c2ecf20Sopenharmony_ci
72288c2ecf20Sopenharmony_ci	if (skb && !skb_in_use) {
72298c2ecf20Sopenharmony_ci		BT_DBG("Freeing %p", skb);
72308c2ecf20Sopenharmony_ci		kfree_skb(skb);
72318c2ecf20Sopenharmony_ci	}
72328c2ecf20Sopenharmony_ci
72338c2ecf20Sopenharmony_ci	return err;
72348c2ecf20Sopenharmony_ci}
72358c2ecf20Sopenharmony_ci
72368c2ecf20Sopenharmony_cistatic int l2cap_finish_move(struct l2cap_chan *chan)
72378c2ecf20Sopenharmony_ci{
72388c2ecf20Sopenharmony_ci	BT_DBG("chan %p", chan);
72398c2ecf20Sopenharmony_ci
72408c2ecf20Sopenharmony_ci	chan->rx_state = L2CAP_RX_STATE_RECV;
72418c2ecf20Sopenharmony_ci
72428c2ecf20Sopenharmony_ci	if (chan->hs_hcon)
72438c2ecf20Sopenharmony_ci		chan->conn->mtu = chan->hs_hcon->hdev->block_mtu;
72448c2ecf20Sopenharmony_ci	else
72458c2ecf20Sopenharmony_ci		chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;
72468c2ecf20Sopenharmony_ci
72478c2ecf20Sopenharmony_ci	return l2cap_resegment(chan);
72488c2ecf20Sopenharmony_ci}
72498c2ecf20Sopenharmony_ci
72508c2ecf20Sopenharmony_cistatic int l2cap_rx_state_wait_p(struct l2cap_chan *chan,
72518c2ecf20Sopenharmony_ci				 struct l2cap_ctrl *control,
72528c2ecf20Sopenharmony_ci				 struct sk_buff *skb, u8 event)
72538c2ecf20Sopenharmony_ci{
72548c2ecf20Sopenharmony_ci	int err;
72558c2ecf20Sopenharmony_ci
72568c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
72578c2ecf20Sopenharmony_ci	       event);
72588c2ecf20Sopenharmony_ci
72598c2ecf20Sopenharmony_ci	if (!control->poll)
72608c2ecf20Sopenharmony_ci		return -EPROTO;
72618c2ecf20Sopenharmony_ci
72628c2ecf20Sopenharmony_ci	l2cap_process_reqseq(chan, control->reqseq);
72638c2ecf20Sopenharmony_ci
72648c2ecf20Sopenharmony_ci	if (!skb_queue_empty(&chan->tx_q))
72658c2ecf20Sopenharmony_ci		chan->tx_send_head = skb_peek(&chan->tx_q);
72668c2ecf20Sopenharmony_ci	else
72678c2ecf20Sopenharmony_ci		chan->tx_send_head = NULL;
72688c2ecf20Sopenharmony_ci
72698c2ecf20Sopenharmony_ci	/* Rewind next_tx_seq to the point expected
72708c2ecf20Sopenharmony_ci	 * by the receiver.
72718c2ecf20Sopenharmony_ci	 */
72728c2ecf20Sopenharmony_ci	chan->next_tx_seq = control->reqseq;
72738c2ecf20Sopenharmony_ci	chan->unacked_frames = 0;
72748c2ecf20Sopenharmony_ci
72758c2ecf20Sopenharmony_ci	err = l2cap_finish_move(chan);
72768c2ecf20Sopenharmony_ci	if (err)
72778c2ecf20Sopenharmony_ci		return err;
72788c2ecf20Sopenharmony_ci
72798c2ecf20Sopenharmony_ci	set_bit(CONN_SEND_FBIT, &chan->conn_state);
72808c2ecf20Sopenharmony_ci	l2cap_send_i_or_rr_or_rnr(chan);
72818c2ecf20Sopenharmony_ci
72828c2ecf20Sopenharmony_ci	if (event == L2CAP_EV_RECV_IFRAME)
72838c2ecf20Sopenharmony_ci		return -EPROTO;
72848c2ecf20Sopenharmony_ci
72858c2ecf20Sopenharmony_ci	return l2cap_rx_state_recv(chan, control, NULL, event);
72868c2ecf20Sopenharmony_ci}
72878c2ecf20Sopenharmony_ci
72888c2ecf20Sopenharmony_cistatic int l2cap_rx_state_wait_f(struct l2cap_chan *chan,
72898c2ecf20Sopenharmony_ci				 struct l2cap_ctrl *control,
72908c2ecf20Sopenharmony_ci				 struct sk_buff *skb, u8 event)
72918c2ecf20Sopenharmony_ci{
72928c2ecf20Sopenharmony_ci	int err;
72938c2ecf20Sopenharmony_ci
72948c2ecf20Sopenharmony_ci	if (!control->final)
72958c2ecf20Sopenharmony_ci		return -EPROTO;
72968c2ecf20Sopenharmony_ci
72978c2ecf20Sopenharmony_ci	clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
72988c2ecf20Sopenharmony_ci
72998c2ecf20Sopenharmony_ci	chan->rx_state = L2CAP_RX_STATE_RECV;
73008c2ecf20Sopenharmony_ci	l2cap_process_reqseq(chan, control->reqseq);
73018c2ecf20Sopenharmony_ci
73028c2ecf20Sopenharmony_ci	if (!skb_queue_empty(&chan->tx_q))
73038c2ecf20Sopenharmony_ci		chan->tx_send_head = skb_peek(&chan->tx_q);
73048c2ecf20Sopenharmony_ci	else
73058c2ecf20Sopenharmony_ci		chan->tx_send_head = NULL;
73068c2ecf20Sopenharmony_ci
73078c2ecf20Sopenharmony_ci	/* Rewind next_tx_seq to the point expected
73088c2ecf20Sopenharmony_ci	 * by the receiver.
73098c2ecf20Sopenharmony_ci	 */
73108c2ecf20Sopenharmony_ci	chan->next_tx_seq = control->reqseq;
73118c2ecf20Sopenharmony_ci	chan->unacked_frames = 0;
73128c2ecf20Sopenharmony_ci
73138c2ecf20Sopenharmony_ci	if (chan->hs_hcon)
73148c2ecf20Sopenharmony_ci		chan->conn->mtu = chan->hs_hcon->hdev->block_mtu;
73158c2ecf20Sopenharmony_ci	else
73168c2ecf20Sopenharmony_ci		chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;
73178c2ecf20Sopenharmony_ci
73188c2ecf20Sopenharmony_ci	err = l2cap_resegment(chan);
73198c2ecf20Sopenharmony_ci
73208c2ecf20Sopenharmony_ci	if (!err)
73218c2ecf20Sopenharmony_ci		err = l2cap_rx_state_recv(chan, control, skb, event);
73228c2ecf20Sopenharmony_ci
73238c2ecf20Sopenharmony_ci	return err;
73248c2ecf20Sopenharmony_ci}
73258c2ecf20Sopenharmony_ci
73268c2ecf20Sopenharmony_cistatic bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq)
73278c2ecf20Sopenharmony_ci{
73288c2ecf20Sopenharmony_ci	/* Make sure reqseq is for a packet that has been sent but not acked */
73298c2ecf20Sopenharmony_ci	u16 unacked;
73308c2ecf20Sopenharmony_ci
73318c2ecf20Sopenharmony_ci	unacked = __seq_offset(chan, chan->next_tx_seq, chan->expected_ack_seq);
73328c2ecf20Sopenharmony_ci	return __seq_offset(chan, chan->next_tx_seq, reqseq) <= unacked;
73338c2ecf20Sopenharmony_ci}
73348c2ecf20Sopenharmony_ci
73358c2ecf20Sopenharmony_cistatic int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
73368c2ecf20Sopenharmony_ci		    struct sk_buff *skb, u8 event)
73378c2ecf20Sopenharmony_ci{
73388c2ecf20Sopenharmony_ci	int err = 0;
73398c2ecf20Sopenharmony_ci
73408c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p, skb %p, event %d, state %d", chan,
73418c2ecf20Sopenharmony_ci	       control, skb, event, chan->rx_state);
73428c2ecf20Sopenharmony_ci
73438c2ecf20Sopenharmony_ci	if (__valid_reqseq(chan, control->reqseq)) {
73448c2ecf20Sopenharmony_ci		switch (chan->rx_state) {
73458c2ecf20Sopenharmony_ci		case L2CAP_RX_STATE_RECV:
73468c2ecf20Sopenharmony_ci			err = l2cap_rx_state_recv(chan, control, skb, event);
73478c2ecf20Sopenharmony_ci			break;
73488c2ecf20Sopenharmony_ci		case L2CAP_RX_STATE_SREJ_SENT:
73498c2ecf20Sopenharmony_ci			err = l2cap_rx_state_srej_sent(chan, control, skb,
73508c2ecf20Sopenharmony_ci						       event);
73518c2ecf20Sopenharmony_ci			break;
73528c2ecf20Sopenharmony_ci		case L2CAP_RX_STATE_WAIT_P:
73538c2ecf20Sopenharmony_ci			err = l2cap_rx_state_wait_p(chan, control, skb, event);
73548c2ecf20Sopenharmony_ci			break;
73558c2ecf20Sopenharmony_ci		case L2CAP_RX_STATE_WAIT_F:
73568c2ecf20Sopenharmony_ci			err = l2cap_rx_state_wait_f(chan, control, skb, event);
73578c2ecf20Sopenharmony_ci			break;
73588c2ecf20Sopenharmony_ci		default:
73598c2ecf20Sopenharmony_ci			/* shut it down */
73608c2ecf20Sopenharmony_ci			break;
73618c2ecf20Sopenharmony_ci		}
73628c2ecf20Sopenharmony_ci	} else {
73638c2ecf20Sopenharmony_ci		BT_DBG("Invalid reqseq %d (next_tx_seq %d, expected_ack_seq %d",
73648c2ecf20Sopenharmony_ci		       control->reqseq, chan->next_tx_seq,
73658c2ecf20Sopenharmony_ci		       chan->expected_ack_seq);
73668c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
73678c2ecf20Sopenharmony_ci	}
73688c2ecf20Sopenharmony_ci
73698c2ecf20Sopenharmony_ci	return err;
73708c2ecf20Sopenharmony_ci}
73718c2ecf20Sopenharmony_ci
73728c2ecf20Sopenharmony_cistatic int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
73738c2ecf20Sopenharmony_ci			   struct sk_buff *skb)
73748c2ecf20Sopenharmony_ci{
73758c2ecf20Sopenharmony_ci	/* l2cap_reassemble_sdu may free skb, hence invalidate control, so store
73768c2ecf20Sopenharmony_ci	 * the txseq field in advance to use it after l2cap_reassemble_sdu
73778c2ecf20Sopenharmony_ci	 * returns and to avoid the race condition, for example:
73788c2ecf20Sopenharmony_ci	 *
73798c2ecf20Sopenharmony_ci	 * The current thread calls:
73808c2ecf20Sopenharmony_ci	 *   l2cap_reassemble_sdu
73818c2ecf20Sopenharmony_ci	 *     chan->ops->recv == l2cap_sock_recv_cb
73828c2ecf20Sopenharmony_ci	 *       __sock_queue_rcv_skb
73838c2ecf20Sopenharmony_ci	 * Another thread calls:
73848c2ecf20Sopenharmony_ci	 *   bt_sock_recvmsg
73858c2ecf20Sopenharmony_ci	 *     skb_recv_datagram
73868c2ecf20Sopenharmony_ci	 *     skb_free_datagram
73878c2ecf20Sopenharmony_ci	 * Then the current thread tries to access control, but it was freed by
73888c2ecf20Sopenharmony_ci	 * skb_free_datagram.
73898c2ecf20Sopenharmony_ci	 */
73908c2ecf20Sopenharmony_ci	u16 txseq = control->txseq;
73918c2ecf20Sopenharmony_ci
73928c2ecf20Sopenharmony_ci	BT_DBG("chan %p, control %p, skb %p, state %d", chan, control, skb,
73938c2ecf20Sopenharmony_ci	       chan->rx_state);
73948c2ecf20Sopenharmony_ci
73958c2ecf20Sopenharmony_ci	if (l2cap_classify_txseq(chan, txseq) == L2CAP_TXSEQ_EXPECTED) {
73968c2ecf20Sopenharmony_ci		l2cap_pass_to_tx(chan, control);
73978c2ecf20Sopenharmony_ci
73988c2ecf20Sopenharmony_ci		BT_DBG("buffer_seq %d->%d", chan->buffer_seq,
73998c2ecf20Sopenharmony_ci		       __next_seq(chan, chan->buffer_seq));
74008c2ecf20Sopenharmony_ci
74018c2ecf20Sopenharmony_ci		chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
74028c2ecf20Sopenharmony_ci
74038c2ecf20Sopenharmony_ci		l2cap_reassemble_sdu(chan, skb, control);
74048c2ecf20Sopenharmony_ci	} else {
74058c2ecf20Sopenharmony_ci		if (chan->sdu) {
74068c2ecf20Sopenharmony_ci			kfree_skb(chan->sdu);
74078c2ecf20Sopenharmony_ci			chan->sdu = NULL;
74088c2ecf20Sopenharmony_ci		}
74098c2ecf20Sopenharmony_ci		chan->sdu_last_frag = NULL;
74108c2ecf20Sopenharmony_ci		chan->sdu_len = 0;
74118c2ecf20Sopenharmony_ci
74128c2ecf20Sopenharmony_ci		if (skb) {
74138c2ecf20Sopenharmony_ci			BT_DBG("Freeing %p", skb);
74148c2ecf20Sopenharmony_ci			kfree_skb(skb);
74158c2ecf20Sopenharmony_ci		}
74168c2ecf20Sopenharmony_ci	}
74178c2ecf20Sopenharmony_ci
74188c2ecf20Sopenharmony_ci	chan->last_acked_seq = txseq;
74198c2ecf20Sopenharmony_ci	chan->expected_tx_seq = __next_seq(chan, txseq);
74208c2ecf20Sopenharmony_ci
74218c2ecf20Sopenharmony_ci	return 0;
74228c2ecf20Sopenharmony_ci}
74238c2ecf20Sopenharmony_ci
74248c2ecf20Sopenharmony_cistatic int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
74258c2ecf20Sopenharmony_ci{
74268c2ecf20Sopenharmony_ci	struct l2cap_ctrl *control = &bt_cb(skb)->l2cap;
74278c2ecf20Sopenharmony_ci	u16 len;
74288c2ecf20Sopenharmony_ci	u8 event;
74298c2ecf20Sopenharmony_ci
74308c2ecf20Sopenharmony_ci	__unpack_control(chan, skb);
74318c2ecf20Sopenharmony_ci
74328c2ecf20Sopenharmony_ci	len = skb->len;
74338c2ecf20Sopenharmony_ci
74348c2ecf20Sopenharmony_ci	/*
74358c2ecf20Sopenharmony_ci	 * We can just drop the corrupted I-frame here.
74368c2ecf20Sopenharmony_ci	 * Receiver will miss it and start proper recovery
74378c2ecf20Sopenharmony_ci	 * procedures and ask for retransmission.
74388c2ecf20Sopenharmony_ci	 */
74398c2ecf20Sopenharmony_ci	if (l2cap_check_fcs(chan, skb))
74408c2ecf20Sopenharmony_ci		goto drop;
74418c2ecf20Sopenharmony_ci
74428c2ecf20Sopenharmony_ci	if (!control->sframe && control->sar == L2CAP_SAR_START)
74438c2ecf20Sopenharmony_ci		len -= L2CAP_SDULEN_SIZE;
74448c2ecf20Sopenharmony_ci
74458c2ecf20Sopenharmony_ci	if (chan->fcs == L2CAP_FCS_CRC16)
74468c2ecf20Sopenharmony_ci		len -= L2CAP_FCS_SIZE;
74478c2ecf20Sopenharmony_ci
74488c2ecf20Sopenharmony_ci	if (len > chan->mps) {
74498c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
74508c2ecf20Sopenharmony_ci		goto drop;
74518c2ecf20Sopenharmony_ci	}
74528c2ecf20Sopenharmony_ci
74538c2ecf20Sopenharmony_ci	if (chan->ops->filter) {
74548c2ecf20Sopenharmony_ci		if (chan->ops->filter(chan, skb))
74558c2ecf20Sopenharmony_ci			goto drop;
74568c2ecf20Sopenharmony_ci	}
74578c2ecf20Sopenharmony_ci
74588c2ecf20Sopenharmony_ci	if (!control->sframe) {
74598c2ecf20Sopenharmony_ci		int err;
74608c2ecf20Sopenharmony_ci
74618c2ecf20Sopenharmony_ci		BT_DBG("iframe sar %d, reqseq %d, final %d, txseq %d",
74628c2ecf20Sopenharmony_ci		       control->sar, control->reqseq, control->final,
74638c2ecf20Sopenharmony_ci		       control->txseq);
74648c2ecf20Sopenharmony_ci
74658c2ecf20Sopenharmony_ci		/* Validate F-bit - F=0 always valid, F=1 only
74668c2ecf20Sopenharmony_ci		 * valid in TX WAIT_F
74678c2ecf20Sopenharmony_ci		 */
74688c2ecf20Sopenharmony_ci		if (control->final && chan->tx_state != L2CAP_TX_STATE_WAIT_F)
74698c2ecf20Sopenharmony_ci			goto drop;
74708c2ecf20Sopenharmony_ci
74718c2ecf20Sopenharmony_ci		if (chan->mode != L2CAP_MODE_STREAMING) {
74728c2ecf20Sopenharmony_ci			event = L2CAP_EV_RECV_IFRAME;
74738c2ecf20Sopenharmony_ci			err = l2cap_rx(chan, control, skb, event);
74748c2ecf20Sopenharmony_ci		} else {
74758c2ecf20Sopenharmony_ci			err = l2cap_stream_rx(chan, control, skb);
74768c2ecf20Sopenharmony_ci		}
74778c2ecf20Sopenharmony_ci
74788c2ecf20Sopenharmony_ci		if (err)
74798c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, ECONNRESET);
74808c2ecf20Sopenharmony_ci	} else {
74818c2ecf20Sopenharmony_ci		const u8 rx_func_to_event[4] = {
74828c2ecf20Sopenharmony_ci			L2CAP_EV_RECV_RR, L2CAP_EV_RECV_REJ,
74838c2ecf20Sopenharmony_ci			L2CAP_EV_RECV_RNR, L2CAP_EV_RECV_SREJ
74848c2ecf20Sopenharmony_ci		};
74858c2ecf20Sopenharmony_ci
74868c2ecf20Sopenharmony_ci		/* Only I-frames are expected in streaming mode */
74878c2ecf20Sopenharmony_ci		if (chan->mode == L2CAP_MODE_STREAMING)
74888c2ecf20Sopenharmony_ci			goto drop;
74898c2ecf20Sopenharmony_ci
74908c2ecf20Sopenharmony_ci		BT_DBG("sframe reqseq %d, final %d, poll %d, super %d",
74918c2ecf20Sopenharmony_ci		       control->reqseq, control->final, control->poll,
74928c2ecf20Sopenharmony_ci		       control->super);
74938c2ecf20Sopenharmony_ci
74948c2ecf20Sopenharmony_ci		if (len != 0) {
74958c2ecf20Sopenharmony_ci			BT_ERR("Trailing bytes: %d in sframe", len);
74968c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, ECONNRESET);
74978c2ecf20Sopenharmony_ci			goto drop;
74988c2ecf20Sopenharmony_ci		}
74998c2ecf20Sopenharmony_ci
75008c2ecf20Sopenharmony_ci		/* Validate F and P bits */
75018c2ecf20Sopenharmony_ci		if (control->final && (control->poll ||
75028c2ecf20Sopenharmony_ci				       chan->tx_state != L2CAP_TX_STATE_WAIT_F))
75038c2ecf20Sopenharmony_ci			goto drop;
75048c2ecf20Sopenharmony_ci
75058c2ecf20Sopenharmony_ci		event = rx_func_to_event[control->super];
75068c2ecf20Sopenharmony_ci		if (l2cap_rx(chan, control, skb, event))
75078c2ecf20Sopenharmony_ci			l2cap_send_disconn_req(chan, ECONNRESET);
75088c2ecf20Sopenharmony_ci	}
75098c2ecf20Sopenharmony_ci
75108c2ecf20Sopenharmony_ci	return 0;
75118c2ecf20Sopenharmony_ci
75128c2ecf20Sopenharmony_cidrop:
75138c2ecf20Sopenharmony_ci	kfree_skb(skb);
75148c2ecf20Sopenharmony_ci	return 0;
75158c2ecf20Sopenharmony_ci}
75168c2ecf20Sopenharmony_ci
75178c2ecf20Sopenharmony_cistatic void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
75188c2ecf20Sopenharmony_ci{
75198c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
75208c2ecf20Sopenharmony_ci	struct l2cap_le_credits pkt;
75218c2ecf20Sopenharmony_ci	u16 return_credits;
75228c2ecf20Sopenharmony_ci
75238c2ecf20Sopenharmony_ci	return_credits = (chan->imtu / chan->mps) + 1;
75248c2ecf20Sopenharmony_ci
75258c2ecf20Sopenharmony_ci	if (chan->rx_credits >= return_credits)
75268c2ecf20Sopenharmony_ci		return;
75278c2ecf20Sopenharmony_ci
75288c2ecf20Sopenharmony_ci	return_credits -= chan->rx_credits;
75298c2ecf20Sopenharmony_ci
75308c2ecf20Sopenharmony_ci	BT_DBG("chan %p returning %u credits to sender", chan, return_credits);
75318c2ecf20Sopenharmony_ci
75328c2ecf20Sopenharmony_ci	chan->rx_credits += return_credits;
75338c2ecf20Sopenharmony_ci
75348c2ecf20Sopenharmony_ci	pkt.cid     = cpu_to_le16(chan->scid);
75358c2ecf20Sopenharmony_ci	pkt.credits = cpu_to_le16(return_credits);
75368c2ecf20Sopenharmony_ci
75378c2ecf20Sopenharmony_ci	chan->ident = l2cap_get_ident(conn);
75388c2ecf20Sopenharmony_ci
75398c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt);
75408c2ecf20Sopenharmony_ci}
75418c2ecf20Sopenharmony_ci
75428c2ecf20Sopenharmony_cistatic int l2cap_ecred_recv(struct l2cap_chan *chan, struct sk_buff *skb)
75438c2ecf20Sopenharmony_ci{
75448c2ecf20Sopenharmony_ci	int err;
75458c2ecf20Sopenharmony_ci
75468c2ecf20Sopenharmony_ci	BT_DBG("SDU reassemble complete: chan %p skb->len %u", chan, skb->len);
75478c2ecf20Sopenharmony_ci
75488c2ecf20Sopenharmony_ci	/* Wait recv to confirm reception before updating the credits */
75498c2ecf20Sopenharmony_ci	err = chan->ops->recv(chan, skb);
75508c2ecf20Sopenharmony_ci
75518c2ecf20Sopenharmony_ci	/* Update credits whenever an SDU is received */
75528c2ecf20Sopenharmony_ci	l2cap_chan_le_send_credits(chan);
75538c2ecf20Sopenharmony_ci
75548c2ecf20Sopenharmony_ci	return err;
75558c2ecf20Sopenharmony_ci}
75568c2ecf20Sopenharmony_ci
75578c2ecf20Sopenharmony_cistatic int l2cap_ecred_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
75588c2ecf20Sopenharmony_ci{
75598c2ecf20Sopenharmony_ci	int err;
75608c2ecf20Sopenharmony_ci
75618c2ecf20Sopenharmony_ci	if (!chan->rx_credits) {
75628c2ecf20Sopenharmony_ci		BT_ERR("No credits to receive LE L2CAP data");
75638c2ecf20Sopenharmony_ci		l2cap_send_disconn_req(chan, ECONNRESET);
75648c2ecf20Sopenharmony_ci		return -ENOBUFS;
75658c2ecf20Sopenharmony_ci	}
75668c2ecf20Sopenharmony_ci
75678c2ecf20Sopenharmony_ci	if (chan->imtu < skb->len) {
75688c2ecf20Sopenharmony_ci		BT_ERR("Too big LE L2CAP PDU");
75698c2ecf20Sopenharmony_ci		return -ENOBUFS;
75708c2ecf20Sopenharmony_ci	}
75718c2ecf20Sopenharmony_ci
75728c2ecf20Sopenharmony_ci	chan->rx_credits--;
75738c2ecf20Sopenharmony_ci	BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits);
75748c2ecf20Sopenharmony_ci
75758c2ecf20Sopenharmony_ci	/* Update if remote had run out of credits, this should only happens
75768c2ecf20Sopenharmony_ci	 * if the remote is not using the entire MPS.
75778c2ecf20Sopenharmony_ci	 */
75788c2ecf20Sopenharmony_ci	if (!chan->rx_credits)
75798c2ecf20Sopenharmony_ci		l2cap_chan_le_send_credits(chan);
75808c2ecf20Sopenharmony_ci
75818c2ecf20Sopenharmony_ci	err = 0;
75828c2ecf20Sopenharmony_ci
75838c2ecf20Sopenharmony_ci	if (!chan->sdu) {
75848c2ecf20Sopenharmony_ci		u16 sdu_len;
75858c2ecf20Sopenharmony_ci
75868c2ecf20Sopenharmony_ci		sdu_len = get_unaligned_le16(skb->data);
75878c2ecf20Sopenharmony_ci		skb_pull(skb, L2CAP_SDULEN_SIZE);
75888c2ecf20Sopenharmony_ci
75898c2ecf20Sopenharmony_ci		BT_DBG("Start of new SDU. sdu_len %u skb->len %u imtu %u",
75908c2ecf20Sopenharmony_ci		       sdu_len, skb->len, chan->imtu);
75918c2ecf20Sopenharmony_ci
75928c2ecf20Sopenharmony_ci		if (sdu_len > chan->imtu) {
75938c2ecf20Sopenharmony_ci			BT_ERR("Too big LE L2CAP SDU length received");
75948c2ecf20Sopenharmony_ci			err = -EMSGSIZE;
75958c2ecf20Sopenharmony_ci			goto failed;
75968c2ecf20Sopenharmony_ci		}
75978c2ecf20Sopenharmony_ci
75988c2ecf20Sopenharmony_ci		if (skb->len > sdu_len) {
75998c2ecf20Sopenharmony_ci			BT_ERR("Too much LE L2CAP data received");
76008c2ecf20Sopenharmony_ci			err = -EINVAL;
76018c2ecf20Sopenharmony_ci			goto failed;
76028c2ecf20Sopenharmony_ci		}
76038c2ecf20Sopenharmony_ci
76048c2ecf20Sopenharmony_ci		if (skb->len == sdu_len)
76058c2ecf20Sopenharmony_ci			return l2cap_ecred_recv(chan, skb);
76068c2ecf20Sopenharmony_ci
76078c2ecf20Sopenharmony_ci		chan->sdu = skb;
76088c2ecf20Sopenharmony_ci		chan->sdu_len = sdu_len;
76098c2ecf20Sopenharmony_ci		chan->sdu_last_frag = skb;
76108c2ecf20Sopenharmony_ci
76118c2ecf20Sopenharmony_ci		/* Detect if remote is not able to use the selected MPS */
76128c2ecf20Sopenharmony_ci		if (skb->len + L2CAP_SDULEN_SIZE < chan->mps) {
76138c2ecf20Sopenharmony_ci			u16 mps_len = skb->len + L2CAP_SDULEN_SIZE;
76148c2ecf20Sopenharmony_ci
76158c2ecf20Sopenharmony_ci			/* Adjust the number of credits */
76168c2ecf20Sopenharmony_ci			BT_DBG("chan->mps %u -> %u", chan->mps, mps_len);
76178c2ecf20Sopenharmony_ci			chan->mps = mps_len;
76188c2ecf20Sopenharmony_ci			l2cap_chan_le_send_credits(chan);
76198c2ecf20Sopenharmony_ci		}
76208c2ecf20Sopenharmony_ci
76218c2ecf20Sopenharmony_ci		return 0;
76228c2ecf20Sopenharmony_ci	}
76238c2ecf20Sopenharmony_ci
76248c2ecf20Sopenharmony_ci	BT_DBG("SDU fragment. chan->sdu->len %u skb->len %u chan->sdu_len %u",
76258c2ecf20Sopenharmony_ci	       chan->sdu->len, skb->len, chan->sdu_len);
76268c2ecf20Sopenharmony_ci
76278c2ecf20Sopenharmony_ci	if (chan->sdu->len + skb->len > chan->sdu_len) {
76288c2ecf20Sopenharmony_ci		BT_ERR("Too much LE L2CAP data received");
76298c2ecf20Sopenharmony_ci		err = -EINVAL;
76308c2ecf20Sopenharmony_ci		goto failed;
76318c2ecf20Sopenharmony_ci	}
76328c2ecf20Sopenharmony_ci
76338c2ecf20Sopenharmony_ci	append_skb_frag(chan->sdu, skb, &chan->sdu_last_frag);
76348c2ecf20Sopenharmony_ci	skb = NULL;
76358c2ecf20Sopenharmony_ci
76368c2ecf20Sopenharmony_ci	if (chan->sdu->len == chan->sdu_len) {
76378c2ecf20Sopenharmony_ci		err = l2cap_ecred_recv(chan, chan->sdu);
76388c2ecf20Sopenharmony_ci		if (!err) {
76398c2ecf20Sopenharmony_ci			chan->sdu = NULL;
76408c2ecf20Sopenharmony_ci			chan->sdu_last_frag = NULL;
76418c2ecf20Sopenharmony_ci			chan->sdu_len = 0;
76428c2ecf20Sopenharmony_ci		}
76438c2ecf20Sopenharmony_ci	}
76448c2ecf20Sopenharmony_ci
76458c2ecf20Sopenharmony_cifailed:
76468c2ecf20Sopenharmony_ci	if (err) {
76478c2ecf20Sopenharmony_ci		kfree_skb(skb);
76488c2ecf20Sopenharmony_ci		kfree_skb(chan->sdu);
76498c2ecf20Sopenharmony_ci		chan->sdu = NULL;
76508c2ecf20Sopenharmony_ci		chan->sdu_last_frag = NULL;
76518c2ecf20Sopenharmony_ci		chan->sdu_len = 0;
76528c2ecf20Sopenharmony_ci	}
76538c2ecf20Sopenharmony_ci
76548c2ecf20Sopenharmony_ci	/* We can't return an error here since we took care of the skb
76558c2ecf20Sopenharmony_ci	 * freeing internally. An error return would cause the caller to
76568c2ecf20Sopenharmony_ci	 * do a double-free of the skb.
76578c2ecf20Sopenharmony_ci	 */
76588c2ecf20Sopenharmony_ci	return 0;
76598c2ecf20Sopenharmony_ci}
76608c2ecf20Sopenharmony_ci
76618c2ecf20Sopenharmony_cistatic void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
76628c2ecf20Sopenharmony_ci			       struct sk_buff *skb)
76638c2ecf20Sopenharmony_ci{
76648c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
76658c2ecf20Sopenharmony_ci
76668c2ecf20Sopenharmony_ci	chan = l2cap_get_chan_by_scid(conn, cid);
76678c2ecf20Sopenharmony_ci	if (!chan) {
76688c2ecf20Sopenharmony_ci		if (cid == L2CAP_CID_A2MP) {
76698c2ecf20Sopenharmony_ci			chan = a2mp_channel_create(conn, skb);
76708c2ecf20Sopenharmony_ci			if (!chan) {
76718c2ecf20Sopenharmony_ci				kfree_skb(skb);
76728c2ecf20Sopenharmony_ci				return;
76738c2ecf20Sopenharmony_ci			}
76748c2ecf20Sopenharmony_ci
76758c2ecf20Sopenharmony_ci			l2cap_chan_hold(chan);
76768c2ecf20Sopenharmony_ci			l2cap_chan_lock(chan);
76778c2ecf20Sopenharmony_ci		} else {
76788c2ecf20Sopenharmony_ci			BT_DBG("unknown cid 0x%4.4x", cid);
76798c2ecf20Sopenharmony_ci			/* Drop packet and return */
76808c2ecf20Sopenharmony_ci			kfree_skb(skb);
76818c2ecf20Sopenharmony_ci			return;
76828c2ecf20Sopenharmony_ci		}
76838c2ecf20Sopenharmony_ci	}
76848c2ecf20Sopenharmony_ci
76858c2ecf20Sopenharmony_ci	BT_DBG("chan %p, len %d", chan, skb->len);
76868c2ecf20Sopenharmony_ci
76878c2ecf20Sopenharmony_ci	/* If we receive data on a fixed channel before the info req/rsp
76888c2ecf20Sopenharmony_ci	 * procedure is done simply assume that the channel is supported
76898c2ecf20Sopenharmony_ci	 * and mark it as ready.
76908c2ecf20Sopenharmony_ci	 */
76918c2ecf20Sopenharmony_ci	if (chan->chan_type == L2CAP_CHAN_FIXED)
76928c2ecf20Sopenharmony_ci		l2cap_chan_ready(chan);
76938c2ecf20Sopenharmony_ci
76948c2ecf20Sopenharmony_ci	if (chan->state != BT_CONNECTED)
76958c2ecf20Sopenharmony_ci		goto drop;
76968c2ecf20Sopenharmony_ci
76978c2ecf20Sopenharmony_ci	switch (chan->mode) {
76988c2ecf20Sopenharmony_ci	case L2CAP_MODE_LE_FLOWCTL:
76998c2ecf20Sopenharmony_ci	case L2CAP_MODE_EXT_FLOWCTL:
77008c2ecf20Sopenharmony_ci		if (l2cap_ecred_data_rcv(chan, skb) < 0)
77018c2ecf20Sopenharmony_ci			goto drop;
77028c2ecf20Sopenharmony_ci
77038c2ecf20Sopenharmony_ci		goto done;
77048c2ecf20Sopenharmony_ci
77058c2ecf20Sopenharmony_ci	case L2CAP_MODE_BASIC:
77068c2ecf20Sopenharmony_ci		/* If socket recv buffers overflows we drop data here
77078c2ecf20Sopenharmony_ci		 * which is *bad* because L2CAP has to be reliable.
77088c2ecf20Sopenharmony_ci		 * But we don't have any other choice. L2CAP doesn't
77098c2ecf20Sopenharmony_ci		 * provide flow control mechanism. */
77108c2ecf20Sopenharmony_ci
77118c2ecf20Sopenharmony_ci		if (chan->imtu < skb->len) {
77128c2ecf20Sopenharmony_ci			BT_ERR("Dropping L2CAP data: receive buffer overflow");
77138c2ecf20Sopenharmony_ci			goto drop;
77148c2ecf20Sopenharmony_ci		}
77158c2ecf20Sopenharmony_ci
77168c2ecf20Sopenharmony_ci		if (!chan->ops->recv(chan, skb))
77178c2ecf20Sopenharmony_ci			goto done;
77188c2ecf20Sopenharmony_ci		break;
77198c2ecf20Sopenharmony_ci
77208c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
77218c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
77228c2ecf20Sopenharmony_ci		l2cap_data_rcv(chan, skb);
77238c2ecf20Sopenharmony_ci		goto done;
77248c2ecf20Sopenharmony_ci
77258c2ecf20Sopenharmony_ci	default:
77268c2ecf20Sopenharmony_ci		BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
77278c2ecf20Sopenharmony_ci		break;
77288c2ecf20Sopenharmony_ci	}
77298c2ecf20Sopenharmony_ci
77308c2ecf20Sopenharmony_cidrop:
77318c2ecf20Sopenharmony_ci	kfree_skb(skb);
77328c2ecf20Sopenharmony_ci
77338c2ecf20Sopenharmony_cidone:
77348c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
77358c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
77368c2ecf20Sopenharmony_ci}
77378c2ecf20Sopenharmony_ci
77388c2ecf20Sopenharmony_cistatic void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
77398c2ecf20Sopenharmony_ci				  struct sk_buff *skb)
77408c2ecf20Sopenharmony_ci{
77418c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
77428c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
77438c2ecf20Sopenharmony_ci
77448c2ecf20Sopenharmony_ci	if (hcon->type != ACL_LINK)
77458c2ecf20Sopenharmony_ci		goto free_skb;
77468c2ecf20Sopenharmony_ci
77478c2ecf20Sopenharmony_ci	chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst,
77488c2ecf20Sopenharmony_ci					ACL_LINK);
77498c2ecf20Sopenharmony_ci	if (!chan)
77508c2ecf20Sopenharmony_ci		goto free_skb;
77518c2ecf20Sopenharmony_ci
77528c2ecf20Sopenharmony_ci	BT_DBG("chan %p, len %d", chan, skb->len);
77538c2ecf20Sopenharmony_ci
77548c2ecf20Sopenharmony_ci	if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
77558c2ecf20Sopenharmony_ci		goto drop;
77568c2ecf20Sopenharmony_ci
77578c2ecf20Sopenharmony_ci	if (chan->imtu < skb->len)
77588c2ecf20Sopenharmony_ci		goto drop;
77598c2ecf20Sopenharmony_ci
77608c2ecf20Sopenharmony_ci	/* Store remote BD_ADDR and PSM for msg_name */
77618c2ecf20Sopenharmony_ci	bacpy(&bt_cb(skb)->l2cap.bdaddr, &hcon->dst);
77628c2ecf20Sopenharmony_ci	bt_cb(skb)->l2cap.psm = psm;
77638c2ecf20Sopenharmony_ci
77648c2ecf20Sopenharmony_ci	if (!chan->ops->recv(chan, skb)) {
77658c2ecf20Sopenharmony_ci		l2cap_chan_put(chan);
77668c2ecf20Sopenharmony_ci		return;
77678c2ecf20Sopenharmony_ci	}
77688c2ecf20Sopenharmony_ci
77698c2ecf20Sopenharmony_cidrop:
77708c2ecf20Sopenharmony_ci	l2cap_chan_put(chan);
77718c2ecf20Sopenharmony_cifree_skb:
77728c2ecf20Sopenharmony_ci	kfree_skb(skb);
77738c2ecf20Sopenharmony_ci}
77748c2ecf20Sopenharmony_ci
77758c2ecf20Sopenharmony_cistatic void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
77768c2ecf20Sopenharmony_ci{
77778c2ecf20Sopenharmony_ci	struct l2cap_hdr *lh = (void *) skb->data;
77788c2ecf20Sopenharmony_ci	struct hci_conn *hcon = conn->hcon;
77798c2ecf20Sopenharmony_ci	u16 cid, len;
77808c2ecf20Sopenharmony_ci	__le16 psm;
77818c2ecf20Sopenharmony_ci
77828c2ecf20Sopenharmony_ci	if (hcon->state != BT_CONNECTED) {
77838c2ecf20Sopenharmony_ci		BT_DBG("queueing pending rx skb");
77848c2ecf20Sopenharmony_ci		skb_queue_tail(&conn->pending_rx, skb);
77858c2ecf20Sopenharmony_ci		return;
77868c2ecf20Sopenharmony_ci	}
77878c2ecf20Sopenharmony_ci
77888c2ecf20Sopenharmony_ci	skb_pull(skb, L2CAP_HDR_SIZE);
77898c2ecf20Sopenharmony_ci	cid = __le16_to_cpu(lh->cid);
77908c2ecf20Sopenharmony_ci	len = __le16_to_cpu(lh->len);
77918c2ecf20Sopenharmony_ci
77928c2ecf20Sopenharmony_ci	if (len != skb->len) {
77938c2ecf20Sopenharmony_ci		kfree_skb(skb);
77948c2ecf20Sopenharmony_ci		return;
77958c2ecf20Sopenharmony_ci	}
77968c2ecf20Sopenharmony_ci
77978c2ecf20Sopenharmony_ci	/* Since we can't actively block incoming LE connections we must
77988c2ecf20Sopenharmony_ci	 * at least ensure that we ignore incoming data from them.
77998c2ecf20Sopenharmony_ci	 */
78008c2ecf20Sopenharmony_ci	if (hcon->type == LE_LINK &&
78018c2ecf20Sopenharmony_ci	    hci_bdaddr_list_lookup(&hcon->hdev->reject_list, &hcon->dst,
78028c2ecf20Sopenharmony_ci				   bdaddr_dst_type(hcon))) {
78038c2ecf20Sopenharmony_ci		kfree_skb(skb);
78048c2ecf20Sopenharmony_ci		return;
78058c2ecf20Sopenharmony_ci	}
78068c2ecf20Sopenharmony_ci
78078c2ecf20Sopenharmony_ci	BT_DBG("len %d, cid 0x%4.4x", len, cid);
78088c2ecf20Sopenharmony_ci
78098c2ecf20Sopenharmony_ci	switch (cid) {
78108c2ecf20Sopenharmony_ci	case L2CAP_CID_SIGNALING:
78118c2ecf20Sopenharmony_ci		l2cap_sig_channel(conn, skb);
78128c2ecf20Sopenharmony_ci		break;
78138c2ecf20Sopenharmony_ci
78148c2ecf20Sopenharmony_ci	case L2CAP_CID_CONN_LESS:
78158c2ecf20Sopenharmony_ci		psm = get_unaligned((__le16 *) skb->data);
78168c2ecf20Sopenharmony_ci		skb_pull(skb, L2CAP_PSMLEN_SIZE);
78178c2ecf20Sopenharmony_ci		l2cap_conless_channel(conn, psm, skb);
78188c2ecf20Sopenharmony_ci		break;
78198c2ecf20Sopenharmony_ci
78208c2ecf20Sopenharmony_ci	case L2CAP_CID_LE_SIGNALING:
78218c2ecf20Sopenharmony_ci		l2cap_le_sig_channel(conn, skb);
78228c2ecf20Sopenharmony_ci		break;
78238c2ecf20Sopenharmony_ci
78248c2ecf20Sopenharmony_ci	default:
78258c2ecf20Sopenharmony_ci		l2cap_data_channel(conn, cid, skb);
78268c2ecf20Sopenharmony_ci		break;
78278c2ecf20Sopenharmony_ci	}
78288c2ecf20Sopenharmony_ci}
78298c2ecf20Sopenharmony_ci
78308c2ecf20Sopenharmony_cistatic void process_pending_rx(struct work_struct *work)
78318c2ecf20Sopenharmony_ci{
78328c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
78338c2ecf20Sopenharmony_ci					       pending_rx_work);
78348c2ecf20Sopenharmony_ci	struct sk_buff *skb;
78358c2ecf20Sopenharmony_ci
78368c2ecf20Sopenharmony_ci	BT_DBG("");
78378c2ecf20Sopenharmony_ci
78388c2ecf20Sopenharmony_ci	while ((skb = skb_dequeue(&conn->pending_rx)))
78398c2ecf20Sopenharmony_ci		l2cap_recv_frame(conn, skb);
78408c2ecf20Sopenharmony_ci}
78418c2ecf20Sopenharmony_ci
78428c2ecf20Sopenharmony_cistatic struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon)
78438c2ecf20Sopenharmony_ci{
78448c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = hcon->l2cap_data;
78458c2ecf20Sopenharmony_ci	struct hci_chan *hchan;
78468c2ecf20Sopenharmony_ci
78478c2ecf20Sopenharmony_ci	if (conn)
78488c2ecf20Sopenharmony_ci		return conn;
78498c2ecf20Sopenharmony_ci
78508c2ecf20Sopenharmony_ci	hchan = hci_chan_create(hcon);
78518c2ecf20Sopenharmony_ci	if (!hchan)
78528c2ecf20Sopenharmony_ci		return NULL;
78538c2ecf20Sopenharmony_ci
78548c2ecf20Sopenharmony_ci	conn = kzalloc(sizeof(*conn), GFP_KERNEL);
78558c2ecf20Sopenharmony_ci	if (!conn) {
78568c2ecf20Sopenharmony_ci		hci_chan_del(hchan);
78578c2ecf20Sopenharmony_ci		return NULL;
78588c2ecf20Sopenharmony_ci	}
78598c2ecf20Sopenharmony_ci
78608c2ecf20Sopenharmony_ci	kref_init(&conn->ref);
78618c2ecf20Sopenharmony_ci	hcon->l2cap_data = conn;
78628c2ecf20Sopenharmony_ci	conn->hcon = hci_conn_get(hcon);
78638c2ecf20Sopenharmony_ci	conn->hchan = hchan;
78648c2ecf20Sopenharmony_ci
78658c2ecf20Sopenharmony_ci	BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
78668c2ecf20Sopenharmony_ci
78678c2ecf20Sopenharmony_ci	switch (hcon->type) {
78688c2ecf20Sopenharmony_ci	case LE_LINK:
78698c2ecf20Sopenharmony_ci		if (hcon->hdev->le_mtu) {
78708c2ecf20Sopenharmony_ci			conn->mtu = hcon->hdev->le_mtu;
78718c2ecf20Sopenharmony_ci			break;
78728c2ecf20Sopenharmony_ci		}
78738c2ecf20Sopenharmony_ci		fallthrough;
78748c2ecf20Sopenharmony_ci	default:
78758c2ecf20Sopenharmony_ci		conn->mtu = hcon->hdev->acl_mtu;
78768c2ecf20Sopenharmony_ci		break;
78778c2ecf20Sopenharmony_ci	}
78788c2ecf20Sopenharmony_ci
78798c2ecf20Sopenharmony_ci	conn->feat_mask = 0;
78808c2ecf20Sopenharmony_ci
78818c2ecf20Sopenharmony_ci	conn->local_fixed_chan = L2CAP_FC_SIG_BREDR | L2CAP_FC_CONNLESS;
78828c2ecf20Sopenharmony_ci
78838c2ecf20Sopenharmony_ci	if (hcon->type == ACL_LINK &&
78848c2ecf20Sopenharmony_ci	    hci_dev_test_flag(hcon->hdev, HCI_HS_ENABLED))
78858c2ecf20Sopenharmony_ci		conn->local_fixed_chan |= L2CAP_FC_A2MP;
78868c2ecf20Sopenharmony_ci
78878c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hcon->hdev, HCI_LE_ENABLED) &&
78888c2ecf20Sopenharmony_ci	    (bredr_sc_enabled(hcon->hdev) ||
78898c2ecf20Sopenharmony_ci	     hci_dev_test_flag(hcon->hdev, HCI_FORCE_BREDR_SMP)))
78908c2ecf20Sopenharmony_ci		conn->local_fixed_chan |= L2CAP_FC_SMP_BREDR;
78918c2ecf20Sopenharmony_ci
78928c2ecf20Sopenharmony_ci	mutex_init(&conn->ident_lock);
78938c2ecf20Sopenharmony_ci	mutex_init(&conn->chan_lock);
78948c2ecf20Sopenharmony_ci
78958c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&conn->chan_l);
78968c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&conn->users);
78978c2ecf20Sopenharmony_ci
78988c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
78998c2ecf20Sopenharmony_ci
79008c2ecf20Sopenharmony_ci	skb_queue_head_init(&conn->pending_rx);
79018c2ecf20Sopenharmony_ci	INIT_WORK(&conn->pending_rx_work, process_pending_rx);
79028c2ecf20Sopenharmony_ci	INIT_WORK(&conn->id_addr_update_work, l2cap_conn_update_id_addr);
79038c2ecf20Sopenharmony_ci
79048c2ecf20Sopenharmony_ci	conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
79058c2ecf20Sopenharmony_ci
79068c2ecf20Sopenharmony_ci	return conn;
79078c2ecf20Sopenharmony_ci}
79088c2ecf20Sopenharmony_ci
79098c2ecf20Sopenharmony_cistatic bool is_valid_psm(u16 psm, u8 dst_type) {
79108c2ecf20Sopenharmony_ci	if (!psm)
79118c2ecf20Sopenharmony_ci		return false;
79128c2ecf20Sopenharmony_ci
79138c2ecf20Sopenharmony_ci	if (bdaddr_type_is_le(dst_type))
79148c2ecf20Sopenharmony_ci		return (psm <= 0x00ff);
79158c2ecf20Sopenharmony_ci
79168c2ecf20Sopenharmony_ci	/* PSM must be odd and lsb of upper byte must be 0 */
79178c2ecf20Sopenharmony_ci	return ((psm & 0x0101) == 0x0001);
79188c2ecf20Sopenharmony_ci}
79198c2ecf20Sopenharmony_ci
79208c2ecf20Sopenharmony_cistruct l2cap_chan_data {
79218c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
79228c2ecf20Sopenharmony_ci	struct pid *pid;
79238c2ecf20Sopenharmony_ci	int count;
79248c2ecf20Sopenharmony_ci};
79258c2ecf20Sopenharmony_ci
79268c2ecf20Sopenharmony_cistatic void l2cap_chan_by_pid(struct l2cap_chan *chan, void *data)
79278c2ecf20Sopenharmony_ci{
79288c2ecf20Sopenharmony_ci	struct l2cap_chan_data *d = data;
79298c2ecf20Sopenharmony_ci	struct pid *pid;
79308c2ecf20Sopenharmony_ci
79318c2ecf20Sopenharmony_ci	if (chan == d->chan)
79328c2ecf20Sopenharmony_ci		return;
79338c2ecf20Sopenharmony_ci
79348c2ecf20Sopenharmony_ci	if (!test_bit(FLAG_DEFER_SETUP, &chan->flags))
79358c2ecf20Sopenharmony_ci		return;
79368c2ecf20Sopenharmony_ci
79378c2ecf20Sopenharmony_ci	pid = chan->ops->get_peer_pid(chan);
79388c2ecf20Sopenharmony_ci
79398c2ecf20Sopenharmony_ci	/* Only count deferred channels with the same PID/PSM */
79408c2ecf20Sopenharmony_ci	if (d->pid != pid || chan->psm != d->chan->psm || chan->ident ||
79418c2ecf20Sopenharmony_ci	    chan->mode != L2CAP_MODE_EXT_FLOWCTL || chan->state != BT_CONNECT)
79428c2ecf20Sopenharmony_ci		return;
79438c2ecf20Sopenharmony_ci
79448c2ecf20Sopenharmony_ci	d->count++;
79458c2ecf20Sopenharmony_ci}
79468c2ecf20Sopenharmony_ci
79478c2ecf20Sopenharmony_ciint l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
79488c2ecf20Sopenharmony_ci		       bdaddr_t *dst, u8 dst_type)
79498c2ecf20Sopenharmony_ci{
79508c2ecf20Sopenharmony_ci	struct l2cap_conn *conn;
79518c2ecf20Sopenharmony_ci	struct hci_conn *hcon;
79528c2ecf20Sopenharmony_ci	struct hci_dev *hdev;
79538c2ecf20Sopenharmony_ci	int err;
79548c2ecf20Sopenharmony_ci
79558c2ecf20Sopenharmony_ci	BT_DBG("%pMR -> %pMR (type %u) psm 0x%4.4x mode 0x%2.2x", &chan->src,
79568c2ecf20Sopenharmony_ci	       dst, dst_type, __le16_to_cpu(psm), chan->mode);
79578c2ecf20Sopenharmony_ci
79588c2ecf20Sopenharmony_ci	hdev = hci_get_route(dst, &chan->src, chan->src_type);
79598c2ecf20Sopenharmony_ci	if (!hdev)
79608c2ecf20Sopenharmony_ci		return -EHOSTUNREACH;
79618c2ecf20Sopenharmony_ci
79628c2ecf20Sopenharmony_ci	hci_dev_lock(hdev);
79638c2ecf20Sopenharmony_ci
79648c2ecf20Sopenharmony_ci	if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
79658c2ecf20Sopenharmony_ci	    chan->chan_type != L2CAP_CHAN_RAW) {
79668c2ecf20Sopenharmony_ci		err = -EINVAL;
79678c2ecf20Sopenharmony_ci		goto done;
79688c2ecf20Sopenharmony_ci	}
79698c2ecf20Sopenharmony_ci
79708c2ecf20Sopenharmony_ci	if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !psm) {
79718c2ecf20Sopenharmony_ci		err = -EINVAL;
79728c2ecf20Sopenharmony_ci		goto done;
79738c2ecf20Sopenharmony_ci	}
79748c2ecf20Sopenharmony_ci
79758c2ecf20Sopenharmony_ci	if (chan->chan_type == L2CAP_CHAN_FIXED && !cid) {
79768c2ecf20Sopenharmony_ci		err = -EINVAL;
79778c2ecf20Sopenharmony_ci		goto done;
79788c2ecf20Sopenharmony_ci	}
79798c2ecf20Sopenharmony_ci
79808c2ecf20Sopenharmony_ci	switch (chan->mode) {
79818c2ecf20Sopenharmony_ci	case L2CAP_MODE_BASIC:
79828c2ecf20Sopenharmony_ci		break;
79838c2ecf20Sopenharmony_ci	case L2CAP_MODE_LE_FLOWCTL:
79848c2ecf20Sopenharmony_ci		break;
79858c2ecf20Sopenharmony_ci	case L2CAP_MODE_EXT_FLOWCTL:
79868c2ecf20Sopenharmony_ci		if (!enable_ecred) {
79878c2ecf20Sopenharmony_ci			err = -EOPNOTSUPP;
79888c2ecf20Sopenharmony_ci			goto done;
79898c2ecf20Sopenharmony_ci		}
79908c2ecf20Sopenharmony_ci		break;
79918c2ecf20Sopenharmony_ci	case L2CAP_MODE_ERTM:
79928c2ecf20Sopenharmony_ci	case L2CAP_MODE_STREAMING:
79938c2ecf20Sopenharmony_ci		if (!disable_ertm)
79948c2ecf20Sopenharmony_ci			break;
79958c2ecf20Sopenharmony_ci		fallthrough;
79968c2ecf20Sopenharmony_ci	default:
79978c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
79988c2ecf20Sopenharmony_ci		goto done;
79998c2ecf20Sopenharmony_ci	}
80008c2ecf20Sopenharmony_ci
80018c2ecf20Sopenharmony_ci	switch (chan->state) {
80028c2ecf20Sopenharmony_ci	case BT_CONNECT:
80038c2ecf20Sopenharmony_ci	case BT_CONNECT2:
80048c2ecf20Sopenharmony_ci	case BT_CONFIG:
80058c2ecf20Sopenharmony_ci		/* Already connecting */
80068c2ecf20Sopenharmony_ci		err = 0;
80078c2ecf20Sopenharmony_ci		goto done;
80088c2ecf20Sopenharmony_ci
80098c2ecf20Sopenharmony_ci	case BT_CONNECTED:
80108c2ecf20Sopenharmony_ci		/* Already connected */
80118c2ecf20Sopenharmony_ci		err = -EISCONN;
80128c2ecf20Sopenharmony_ci		goto done;
80138c2ecf20Sopenharmony_ci
80148c2ecf20Sopenharmony_ci	case BT_OPEN:
80158c2ecf20Sopenharmony_ci	case BT_BOUND:
80168c2ecf20Sopenharmony_ci		/* Can connect */
80178c2ecf20Sopenharmony_ci		break;
80188c2ecf20Sopenharmony_ci
80198c2ecf20Sopenharmony_ci	default:
80208c2ecf20Sopenharmony_ci		err = -EBADFD;
80218c2ecf20Sopenharmony_ci		goto done;
80228c2ecf20Sopenharmony_ci	}
80238c2ecf20Sopenharmony_ci
80248c2ecf20Sopenharmony_ci	/* Set destination address and psm */
80258c2ecf20Sopenharmony_ci	bacpy(&chan->dst, dst);
80268c2ecf20Sopenharmony_ci	chan->dst_type = dst_type;
80278c2ecf20Sopenharmony_ci
80288c2ecf20Sopenharmony_ci	chan->psm = psm;
80298c2ecf20Sopenharmony_ci	chan->dcid = cid;
80308c2ecf20Sopenharmony_ci
80318c2ecf20Sopenharmony_ci	if (bdaddr_type_is_le(dst_type)) {
80328c2ecf20Sopenharmony_ci		/* Convert from L2CAP channel address type to HCI address type
80338c2ecf20Sopenharmony_ci		 */
80348c2ecf20Sopenharmony_ci		if (dst_type == BDADDR_LE_PUBLIC)
80358c2ecf20Sopenharmony_ci			dst_type = ADDR_LE_DEV_PUBLIC;
80368c2ecf20Sopenharmony_ci		else
80378c2ecf20Sopenharmony_ci			dst_type = ADDR_LE_DEV_RANDOM;
80388c2ecf20Sopenharmony_ci
80398c2ecf20Sopenharmony_ci		if (hci_dev_test_flag(hdev, HCI_ADVERTISING))
80408c2ecf20Sopenharmony_ci			hcon = hci_connect_le(hdev, dst, dst_type,
80418c2ecf20Sopenharmony_ci					      chan->sec_level,
80428c2ecf20Sopenharmony_ci					      HCI_LE_CONN_TIMEOUT,
80438c2ecf20Sopenharmony_ci					      HCI_ROLE_SLAVE, NULL);
80448c2ecf20Sopenharmony_ci		else
80458c2ecf20Sopenharmony_ci			hcon = hci_connect_le_scan(hdev, dst, dst_type,
80468c2ecf20Sopenharmony_ci						   chan->sec_level,
80478c2ecf20Sopenharmony_ci						   HCI_LE_CONN_TIMEOUT,
80488c2ecf20Sopenharmony_ci						   CONN_REASON_L2CAP_CHAN);
80498c2ecf20Sopenharmony_ci
80508c2ecf20Sopenharmony_ci	} else {
80518c2ecf20Sopenharmony_ci		u8 auth_type = l2cap_get_auth_type(chan);
80528c2ecf20Sopenharmony_ci		hcon = hci_connect_acl(hdev, dst, chan->sec_level, auth_type,
80538c2ecf20Sopenharmony_ci				       CONN_REASON_L2CAP_CHAN);
80548c2ecf20Sopenharmony_ci	}
80558c2ecf20Sopenharmony_ci
80568c2ecf20Sopenharmony_ci	if (IS_ERR(hcon)) {
80578c2ecf20Sopenharmony_ci		err = PTR_ERR(hcon);
80588c2ecf20Sopenharmony_ci		goto done;
80598c2ecf20Sopenharmony_ci	}
80608c2ecf20Sopenharmony_ci
80618c2ecf20Sopenharmony_ci	conn = l2cap_conn_add(hcon);
80628c2ecf20Sopenharmony_ci	if (!conn) {
80638c2ecf20Sopenharmony_ci		hci_conn_drop(hcon);
80648c2ecf20Sopenharmony_ci		err = -ENOMEM;
80658c2ecf20Sopenharmony_ci		goto done;
80668c2ecf20Sopenharmony_ci	}
80678c2ecf20Sopenharmony_ci
80688c2ecf20Sopenharmony_ci	if (chan->mode == L2CAP_MODE_EXT_FLOWCTL) {
80698c2ecf20Sopenharmony_ci		struct l2cap_chan_data data;
80708c2ecf20Sopenharmony_ci
80718c2ecf20Sopenharmony_ci		data.chan = chan;
80728c2ecf20Sopenharmony_ci		data.pid = chan->ops->get_peer_pid(chan);
80738c2ecf20Sopenharmony_ci		data.count = 1;
80748c2ecf20Sopenharmony_ci
80758c2ecf20Sopenharmony_ci		l2cap_chan_list(conn, l2cap_chan_by_pid, &data);
80768c2ecf20Sopenharmony_ci
80778c2ecf20Sopenharmony_ci		/* Check if there isn't too many channels being connected */
80788c2ecf20Sopenharmony_ci		if (data.count > L2CAP_ECRED_CONN_SCID_MAX) {
80798c2ecf20Sopenharmony_ci			hci_conn_drop(hcon);
80808c2ecf20Sopenharmony_ci			err = -EPROTO;
80818c2ecf20Sopenharmony_ci			goto done;
80828c2ecf20Sopenharmony_ci		}
80838c2ecf20Sopenharmony_ci	}
80848c2ecf20Sopenharmony_ci
80858c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
80868c2ecf20Sopenharmony_ci	l2cap_chan_lock(chan);
80878c2ecf20Sopenharmony_ci
80888c2ecf20Sopenharmony_ci	if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
80898c2ecf20Sopenharmony_ci		hci_conn_drop(hcon);
80908c2ecf20Sopenharmony_ci		err = -EBUSY;
80918c2ecf20Sopenharmony_ci		goto chan_unlock;
80928c2ecf20Sopenharmony_ci	}
80938c2ecf20Sopenharmony_ci
80948c2ecf20Sopenharmony_ci	/* Update source addr of the socket */
80958c2ecf20Sopenharmony_ci	bacpy(&chan->src, &hcon->src);
80968c2ecf20Sopenharmony_ci	chan->src_type = bdaddr_src_type(hcon);
80978c2ecf20Sopenharmony_ci
80988c2ecf20Sopenharmony_ci	__l2cap_chan_add(conn, chan);
80998c2ecf20Sopenharmony_ci
81008c2ecf20Sopenharmony_ci	/* l2cap_chan_add takes its own ref so we can drop this one */
81018c2ecf20Sopenharmony_ci	hci_conn_drop(hcon);
81028c2ecf20Sopenharmony_ci
81038c2ecf20Sopenharmony_ci	l2cap_state_change(chan, BT_CONNECT);
81048c2ecf20Sopenharmony_ci	__set_chan_timer(chan, chan->ops->get_sndtimeo(chan));
81058c2ecf20Sopenharmony_ci
81068c2ecf20Sopenharmony_ci	/* Release chan->sport so that it can be reused by other
81078c2ecf20Sopenharmony_ci	 * sockets (as it's only used for listening sockets).
81088c2ecf20Sopenharmony_ci	 */
81098c2ecf20Sopenharmony_ci	write_lock(&chan_list_lock);
81108c2ecf20Sopenharmony_ci	chan->sport = 0;
81118c2ecf20Sopenharmony_ci	write_unlock(&chan_list_lock);
81128c2ecf20Sopenharmony_ci
81138c2ecf20Sopenharmony_ci	if (hcon->state == BT_CONNECTED) {
81148c2ecf20Sopenharmony_ci		if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
81158c2ecf20Sopenharmony_ci			__clear_chan_timer(chan);
81168c2ecf20Sopenharmony_ci			if (l2cap_chan_check_security(chan, true))
81178c2ecf20Sopenharmony_ci				l2cap_state_change(chan, BT_CONNECTED);
81188c2ecf20Sopenharmony_ci		} else
81198c2ecf20Sopenharmony_ci			l2cap_do_start(chan);
81208c2ecf20Sopenharmony_ci	}
81218c2ecf20Sopenharmony_ci
81228c2ecf20Sopenharmony_ci	err = 0;
81238c2ecf20Sopenharmony_ci
81248c2ecf20Sopenharmony_cichan_unlock:
81258c2ecf20Sopenharmony_ci	l2cap_chan_unlock(chan);
81268c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
81278c2ecf20Sopenharmony_cidone:
81288c2ecf20Sopenharmony_ci	hci_dev_unlock(hdev);
81298c2ecf20Sopenharmony_ci	hci_dev_put(hdev);
81308c2ecf20Sopenharmony_ci	return err;
81318c2ecf20Sopenharmony_ci}
81328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(l2cap_chan_connect);
81338c2ecf20Sopenharmony_ci
81348c2ecf20Sopenharmony_cistatic void l2cap_ecred_reconfigure(struct l2cap_chan *chan)
81358c2ecf20Sopenharmony_ci{
81368c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = chan->conn;
81378c2ecf20Sopenharmony_ci	struct {
81388c2ecf20Sopenharmony_ci		struct l2cap_ecred_reconf_req req;
81398c2ecf20Sopenharmony_ci		__le16 scid;
81408c2ecf20Sopenharmony_ci	} pdu;
81418c2ecf20Sopenharmony_ci
81428c2ecf20Sopenharmony_ci	pdu.req.mtu = cpu_to_le16(chan->imtu);
81438c2ecf20Sopenharmony_ci	pdu.req.mps = cpu_to_le16(chan->mps);
81448c2ecf20Sopenharmony_ci	pdu.scid    = cpu_to_le16(chan->scid);
81458c2ecf20Sopenharmony_ci
81468c2ecf20Sopenharmony_ci	chan->ident = l2cap_get_ident(conn);
81478c2ecf20Sopenharmony_ci
81488c2ecf20Sopenharmony_ci	l2cap_send_cmd(conn, chan->ident, L2CAP_ECRED_RECONF_REQ,
81498c2ecf20Sopenharmony_ci		       sizeof(pdu), &pdu);
81508c2ecf20Sopenharmony_ci}
81518c2ecf20Sopenharmony_ci
81528c2ecf20Sopenharmony_ciint l2cap_chan_reconfigure(struct l2cap_chan *chan, __u16 mtu)
81538c2ecf20Sopenharmony_ci{
81548c2ecf20Sopenharmony_ci	if (chan->imtu > mtu)
81558c2ecf20Sopenharmony_ci		return -EINVAL;
81568c2ecf20Sopenharmony_ci
81578c2ecf20Sopenharmony_ci	BT_DBG("chan %p mtu 0x%4.4x", chan, mtu);
81588c2ecf20Sopenharmony_ci
81598c2ecf20Sopenharmony_ci	chan->imtu = mtu;
81608c2ecf20Sopenharmony_ci
81618c2ecf20Sopenharmony_ci	l2cap_ecred_reconfigure(chan);
81628c2ecf20Sopenharmony_ci
81638c2ecf20Sopenharmony_ci	return 0;
81648c2ecf20Sopenharmony_ci}
81658c2ecf20Sopenharmony_ci
81668c2ecf20Sopenharmony_ci/* ---- L2CAP interface with lower layer (HCI) ---- */
81678c2ecf20Sopenharmony_ci
81688c2ecf20Sopenharmony_ciint l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
81698c2ecf20Sopenharmony_ci{
81708c2ecf20Sopenharmony_ci	int exact = 0, lm1 = 0, lm2 = 0;
81718c2ecf20Sopenharmony_ci	struct l2cap_chan *c;
81728c2ecf20Sopenharmony_ci
81738c2ecf20Sopenharmony_ci	BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
81748c2ecf20Sopenharmony_ci
81758c2ecf20Sopenharmony_ci	/* Find listening sockets and check their link_mode */
81768c2ecf20Sopenharmony_ci	read_lock(&chan_list_lock);
81778c2ecf20Sopenharmony_ci	list_for_each_entry(c, &chan_list, global_l) {
81788c2ecf20Sopenharmony_ci		if (c->state != BT_LISTEN)
81798c2ecf20Sopenharmony_ci			continue;
81808c2ecf20Sopenharmony_ci
81818c2ecf20Sopenharmony_ci		if (!bacmp(&c->src, &hdev->bdaddr)) {
81828c2ecf20Sopenharmony_ci			lm1 |= HCI_LM_ACCEPT;
81838c2ecf20Sopenharmony_ci			if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
81848c2ecf20Sopenharmony_ci				lm1 |= HCI_LM_MASTER;
81858c2ecf20Sopenharmony_ci			exact++;
81868c2ecf20Sopenharmony_ci		} else if (!bacmp(&c->src, BDADDR_ANY)) {
81878c2ecf20Sopenharmony_ci			lm2 |= HCI_LM_ACCEPT;
81888c2ecf20Sopenharmony_ci			if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
81898c2ecf20Sopenharmony_ci				lm2 |= HCI_LM_MASTER;
81908c2ecf20Sopenharmony_ci		}
81918c2ecf20Sopenharmony_ci	}
81928c2ecf20Sopenharmony_ci	read_unlock(&chan_list_lock);
81938c2ecf20Sopenharmony_ci
81948c2ecf20Sopenharmony_ci	return exact ? lm1 : lm2;
81958c2ecf20Sopenharmony_ci}
81968c2ecf20Sopenharmony_ci
81978c2ecf20Sopenharmony_ci/* Find the next fixed channel in BT_LISTEN state, continue iteration
81988c2ecf20Sopenharmony_ci * from an existing channel in the list or from the beginning of the
81998c2ecf20Sopenharmony_ci * global list (by passing NULL as first parameter).
82008c2ecf20Sopenharmony_ci */
82018c2ecf20Sopenharmony_cistatic struct l2cap_chan *l2cap_global_fixed_chan(struct l2cap_chan *c,
82028c2ecf20Sopenharmony_ci						  struct hci_conn *hcon)
82038c2ecf20Sopenharmony_ci{
82048c2ecf20Sopenharmony_ci	u8 src_type = bdaddr_src_type(hcon);
82058c2ecf20Sopenharmony_ci
82068c2ecf20Sopenharmony_ci	read_lock(&chan_list_lock);
82078c2ecf20Sopenharmony_ci
82088c2ecf20Sopenharmony_ci	if (c)
82098c2ecf20Sopenharmony_ci		c = list_next_entry(c, global_l);
82108c2ecf20Sopenharmony_ci	else
82118c2ecf20Sopenharmony_ci		c = list_entry(chan_list.next, typeof(*c), global_l);
82128c2ecf20Sopenharmony_ci
82138c2ecf20Sopenharmony_ci	list_for_each_entry_from(c, &chan_list, global_l) {
82148c2ecf20Sopenharmony_ci		if (c->chan_type != L2CAP_CHAN_FIXED)
82158c2ecf20Sopenharmony_ci			continue;
82168c2ecf20Sopenharmony_ci		if (c->state != BT_LISTEN)
82178c2ecf20Sopenharmony_ci			continue;
82188c2ecf20Sopenharmony_ci		if (bacmp(&c->src, &hcon->src) && bacmp(&c->src, BDADDR_ANY))
82198c2ecf20Sopenharmony_ci			continue;
82208c2ecf20Sopenharmony_ci		if (src_type != c->src_type)
82218c2ecf20Sopenharmony_ci			continue;
82228c2ecf20Sopenharmony_ci
82238c2ecf20Sopenharmony_ci		c = l2cap_chan_hold_unless_zero(c);
82248c2ecf20Sopenharmony_ci		read_unlock(&chan_list_lock);
82258c2ecf20Sopenharmony_ci		return c;
82268c2ecf20Sopenharmony_ci	}
82278c2ecf20Sopenharmony_ci
82288c2ecf20Sopenharmony_ci	read_unlock(&chan_list_lock);
82298c2ecf20Sopenharmony_ci
82308c2ecf20Sopenharmony_ci	return NULL;
82318c2ecf20Sopenharmony_ci}
82328c2ecf20Sopenharmony_ci
82338c2ecf20Sopenharmony_cistatic void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
82348c2ecf20Sopenharmony_ci{
82358c2ecf20Sopenharmony_ci	struct hci_dev *hdev = hcon->hdev;
82368c2ecf20Sopenharmony_ci	struct l2cap_conn *conn;
82378c2ecf20Sopenharmony_ci	struct l2cap_chan *pchan;
82388c2ecf20Sopenharmony_ci	u8 dst_type;
82398c2ecf20Sopenharmony_ci
82408c2ecf20Sopenharmony_ci	if (hcon->type != ACL_LINK && hcon->type != LE_LINK)
82418c2ecf20Sopenharmony_ci		return;
82428c2ecf20Sopenharmony_ci
82438c2ecf20Sopenharmony_ci	BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
82448c2ecf20Sopenharmony_ci
82458c2ecf20Sopenharmony_ci	if (status) {
82468c2ecf20Sopenharmony_ci		l2cap_conn_del(hcon, bt_to_errno(status));
82478c2ecf20Sopenharmony_ci		return;
82488c2ecf20Sopenharmony_ci	}
82498c2ecf20Sopenharmony_ci
82508c2ecf20Sopenharmony_ci	conn = l2cap_conn_add(hcon);
82518c2ecf20Sopenharmony_ci	if (!conn)
82528c2ecf20Sopenharmony_ci		return;
82538c2ecf20Sopenharmony_ci
82548c2ecf20Sopenharmony_ci	dst_type = bdaddr_dst_type(hcon);
82558c2ecf20Sopenharmony_ci
82568c2ecf20Sopenharmony_ci	/* If device is blocked, do not create channels for it */
82578c2ecf20Sopenharmony_ci	if (hci_bdaddr_list_lookup(&hdev->reject_list, &hcon->dst, dst_type))
82588c2ecf20Sopenharmony_ci		return;
82598c2ecf20Sopenharmony_ci
82608c2ecf20Sopenharmony_ci	/* Find fixed channels and notify them of the new connection. We
82618c2ecf20Sopenharmony_ci	 * use multiple individual lookups, continuing each time where
82628c2ecf20Sopenharmony_ci	 * we left off, because the list lock would prevent calling the
82638c2ecf20Sopenharmony_ci	 * potentially sleeping l2cap_chan_lock() function.
82648c2ecf20Sopenharmony_ci	 */
82658c2ecf20Sopenharmony_ci	pchan = l2cap_global_fixed_chan(NULL, hcon);
82668c2ecf20Sopenharmony_ci	while (pchan) {
82678c2ecf20Sopenharmony_ci		struct l2cap_chan *chan, *next;
82688c2ecf20Sopenharmony_ci
82698c2ecf20Sopenharmony_ci		/* Client fixed channels should override server ones */
82708c2ecf20Sopenharmony_ci		if (__l2cap_get_chan_by_dcid(conn, pchan->scid))
82718c2ecf20Sopenharmony_ci			goto next;
82728c2ecf20Sopenharmony_ci
82738c2ecf20Sopenharmony_ci		l2cap_chan_lock(pchan);
82748c2ecf20Sopenharmony_ci		chan = pchan->ops->new_connection(pchan);
82758c2ecf20Sopenharmony_ci		if (chan) {
82768c2ecf20Sopenharmony_ci			bacpy(&chan->src, &hcon->src);
82778c2ecf20Sopenharmony_ci			bacpy(&chan->dst, &hcon->dst);
82788c2ecf20Sopenharmony_ci			chan->src_type = bdaddr_src_type(hcon);
82798c2ecf20Sopenharmony_ci			chan->dst_type = dst_type;
82808c2ecf20Sopenharmony_ci
82818c2ecf20Sopenharmony_ci			__l2cap_chan_add(conn, chan);
82828c2ecf20Sopenharmony_ci		}
82838c2ecf20Sopenharmony_ci
82848c2ecf20Sopenharmony_ci		l2cap_chan_unlock(pchan);
82858c2ecf20Sopenharmony_cinext:
82868c2ecf20Sopenharmony_ci		next = l2cap_global_fixed_chan(pchan, hcon);
82878c2ecf20Sopenharmony_ci		l2cap_chan_put(pchan);
82888c2ecf20Sopenharmony_ci		pchan = next;
82898c2ecf20Sopenharmony_ci	}
82908c2ecf20Sopenharmony_ci
82918c2ecf20Sopenharmony_ci	l2cap_conn_ready(conn);
82928c2ecf20Sopenharmony_ci}
82938c2ecf20Sopenharmony_ci
82948c2ecf20Sopenharmony_ciint l2cap_disconn_ind(struct hci_conn *hcon)
82958c2ecf20Sopenharmony_ci{
82968c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = hcon->l2cap_data;
82978c2ecf20Sopenharmony_ci
82988c2ecf20Sopenharmony_ci	BT_DBG("hcon %p", hcon);
82998c2ecf20Sopenharmony_ci
83008c2ecf20Sopenharmony_ci	if (!conn)
83018c2ecf20Sopenharmony_ci		return HCI_ERROR_REMOTE_USER_TERM;
83028c2ecf20Sopenharmony_ci	return conn->disc_reason;
83038c2ecf20Sopenharmony_ci}
83048c2ecf20Sopenharmony_ci
83058c2ecf20Sopenharmony_cistatic void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
83068c2ecf20Sopenharmony_ci{
83078c2ecf20Sopenharmony_ci	if (hcon->type != ACL_LINK && hcon->type != LE_LINK)
83088c2ecf20Sopenharmony_ci		return;
83098c2ecf20Sopenharmony_ci
83108c2ecf20Sopenharmony_ci	BT_DBG("hcon %p reason %d", hcon, reason);
83118c2ecf20Sopenharmony_ci
83128c2ecf20Sopenharmony_ci	l2cap_conn_del(hcon, bt_to_errno(reason));
83138c2ecf20Sopenharmony_ci}
83148c2ecf20Sopenharmony_ci
83158c2ecf20Sopenharmony_cistatic inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
83168c2ecf20Sopenharmony_ci{
83178c2ecf20Sopenharmony_ci	if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
83188c2ecf20Sopenharmony_ci		return;
83198c2ecf20Sopenharmony_ci
83208c2ecf20Sopenharmony_ci	if (encrypt == 0x00) {
83218c2ecf20Sopenharmony_ci		if (chan->sec_level == BT_SECURITY_MEDIUM) {
83228c2ecf20Sopenharmony_ci			__set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
83238c2ecf20Sopenharmony_ci		} else if (chan->sec_level == BT_SECURITY_HIGH ||
83248c2ecf20Sopenharmony_ci			   chan->sec_level == BT_SECURITY_FIPS)
83258c2ecf20Sopenharmony_ci			l2cap_chan_close(chan, ECONNREFUSED);
83268c2ecf20Sopenharmony_ci	} else {
83278c2ecf20Sopenharmony_ci		if (chan->sec_level == BT_SECURITY_MEDIUM)
83288c2ecf20Sopenharmony_ci			__clear_chan_timer(chan);
83298c2ecf20Sopenharmony_ci	}
83308c2ecf20Sopenharmony_ci}
83318c2ecf20Sopenharmony_ci
83328c2ecf20Sopenharmony_cistatic void l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
83338c2ecf20Sopenharmony_ci{
83348c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = hcon->l2cap_data;
83358c2ecf20Sopenharmony_ci	struct l2cap_chan *chan;
83368c2ecf20Sopenharmony_ci
83378c2ecf20Sopenharmony_ci	if (!conn)
83388c2ecf20Sopenharmony_ci		return;
83398c2ecf20Sopenharmony_ci
83408c2ecf20Sopenharmony_ci	BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt);
83418c2ecf20Sopenharmony_ci
83428c2ecf20Sopenharmony_ci	mutex_lock(&conn->chan_lock);
83438c2ecf20Sopenharmony_ci
83448c2ecf20Sopenharmony_ci	list_for_each_entry(chan, &conn->chan_l, list) {
83458c2ecf20Sopenharmony_ci		l2cap_chan_lock(chan);
83468c2ecf20Sopenharmony_ci
83478c2ecf20Sopenharmony_ci		BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,
83488c2ecf20Sopenharmony_ci		       state_to_string(chan->state));
83498c2ecf20Sopenharmony_ci
83508c2ecf20Sopenharmony_ci		if (chan->scid == L2CAP_CID_A2MP) {
83518c2ecf20Sopenharmony_ci			l2cap_chan_unlock(chan);
83528c2ecf20Sopenharmony_ci			continue;
83538c2ecf20Sopenharmony_ci		}
83548c2ecf20Sopenharmony_ci
83558c2ecf20Sopenharmony_ci		if (!status && encrypt)
83568c2ecf20Sopenharmony_ci			chan->sec_level = hcon->sec_level;
83578c2ecf20Sopenharmony_ci
83588c2ecf20Sopenharmony_ci		if (!__l2cap_no_conn_pending(chan)) {
83598c2ecf20Sopenharmony_ci			l2cap_chan_unlock(chan);
83608c2ecf20Sopenharmony_ci			continue;
83618c2ecf20Sopenharmony_ci		}
83628c2ecf20Sopenharmony_ci
83638c2ecf20Sopenharmony_ci		if (!status && (chan->state == BT_CONNECTED ||
83648c2ecf20Sopenharmony_ci				chan->state == BT_CONFIG)) {
83658c2ecf20Sopenharmony_ci			chan->ops->resume(chan);
83668c2ecf20Sopenharmony_ci			l2cap_check_encryption(chan, encrypt);
83678c2ecf20Sopenharmony_ci			l2cap_chan_unlock(chan);
83688c2ecf20Sopenharmony_ci			continue;
83698c2ecf20Sopenharmony_ci		}
83708c2ecf20Sopenharmony_ci
83718c2ecf20Sopenharmony_ci		if (chan->state == BT_CONNECT) {
83728c2ecf20Sopenharmony_ci			if (!status && l2cap_check_enc_key_size(hcon))
83738c2ecf20Sopenharmony_ci				l2cap_start_connection(chan);
83748c2ecf20Sopenharmony_ci			else
83758c2ecf20Sopenharmony_ci				__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
83768c2ecf20Sopenharmony_ci		} else if (chan->state == BT_CONNECT2 &&
83778c2ecf20Sopenharmony_ci			   !(chan->mode == L2CAP_MODE_EXT_FLOWCTL ||
83788c2ecf20Sopenharmony_ci			     chan->mode == L2CAP_MODE_LE_FLOWCTL)) {
83798c2ecf20Sopenharmony_ci			struct l2cap_conn_rsp rsp;
83808c2ecf20Sopenharmony_ci			__u16 res, stat;
83818c2ecf20Sopenharmony_ci
83828c2ecf20Sopenharmony_ci			if (!status && l2cap_check_enc_key_size(hcon)) {
83838c2ecf20Sopenharmony_ci				if (test_bit(FLAG_DEFER_SETUP, &chan->flags)) {
83848c2ecf20Sopenharmony_ci					res = L2CAP_CR_PEND;
83858c2ecf20Sopenharmony_ci					stat = L2CAP_CS_AUTHOR_PEND;
83868c2ecf20Sopenharmony_ci					chan->ops->defer(chan);
83878c2ecf20Sopenharmony_ci				} else {
83888c2ecf20Sopenharmony_ci					l2cap_state_change(chan, BT_CONFIG);
83898c2ecf20Sopenharmony_ci					res = L2CAP_CR_SUCCESS;
83908c2ecf20Sopenharmony_ci					stat = L2CAP_CS_NO_INFO;
83918c2ecf20Sopenharmony_ci				}
83928c2ecf20Sopenharmony_ci			} else {
83938c2ecf20Sopenharmony_ci				l2cap_state_change(chan, BT_DISCONN);
83948c2ecf20Sopenharmony_ci				__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
83958c2ecf20Sopenharmony_ci				res = L2CAP_CR_SEC_BLOCK;
83968c2ecf20Sopenharmony_ci				stat = L2CAP_CS_NO_INFO;
83978c2ecf20Sopenharmony_ci			}
83988c2ecf20Sopenharmony_ci
83998c2ecf20Sopenharmony_ci			rsp.scid   = cpu_to_le16(chan->dcid);
84008c2ecf20Sopenharmony_ci			rsp.dcid   = cpu_to_le16(chan->scid);
84018c2ecf20Sopenharmony_ci			rsp.result = cpu_to_le16(res);
84028c2ecf20Sopenharmony_ci			rsp.status = cpu_to_le16(stat);
84038c2ecf20Sopenharmony_ci			l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
84048c2ecf20Sopenharmony_ci				       sizeof(rsp), &rsp);
84058c2ecf20Sopenharmony_ci
84068c2ecf20Sopenharmony_ci			if (!test_bit(CONF_REQ_SENT, &chan->conf_state) &&
84078c2ecf20Sopenharmony_ci			    res == L2CAP_CR_SUCCESS) {
84088c2ecf20Sopenharmony_ci				char buf[128];
84098c2ecf20Sopenharmony_ci				set_bit(CONF_REQ_SENT, &chan->conf_state);
84108c2ecf20Sopenharmony_ci				l2cap_send_cmd(conn, l2cap_get_ident(conn),
84118c2ecf20Sopenharmony_ci					       L2CAP_CONF_REQ,
84128c2ecf20Sopenharmony_ci					       l2cap_build_conf_req(chan, buf, sizeof(buf)),
84138c2ecf20Sopenharmony_ci					       buf);
84148c2ecf20Sopenharmony_ci				chan->num_conf_req++;
84158c2ecf20Sopenharmony_ci			}
84168c2ecf20Sopenharmony_ci		}
84178c2ecf20Sopenharmony_ci
84188c2ecf20Sopenharmony_ci		l2cap_chan_unlock(chan);
84198c2ecf20Sopenharmony_ci	}
84208c2ecf20Sopenharmony_ci
84218c2ecf20Sopenharmony_ci	mutex_unlock(&conn->chan_lock);
84228c2ecf20Sopenharmony_ci}
84238c2ecf20Sopenharmony_ci
84248c2ecf20Sopenharmony_civoid l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
84258c2ecf20Sopenharmony_ci{
84268c2ecf20Sopenharmony_ci	struct l2cap_conn *conn = hcon->l2cap_data;
84278c2ecf20Sopenharmony_ci	struct l2cap_hdr *hdr;
84288c2ecf20Sopenharmony_ci	int len;
84298c2ecf20Sopenharmony_ci
84308c2ecf20Sopenharmony_ci	/* For AMP controller do not create l2cap conn */
84318c2ecf20Sopenharmony_ci	if (!conn && hcon->hdev->dev_type != HCI_PRIMARY)
84328c2ecf20Sopenharmony_ci		goto drop;
84338c2ecf20Sopenharmony_ci
84348c2ecf20Sopenharmony_ci	if (!conn)
84358c2ecf20Sopenharmony_ci		conn = l2cap_conn_add(hcon);
84368c2ecf20Sopenharmony_ci
84378c2ecf20Sopenharmony_ci	if (!conn)
84388c2ecf20Sopenharmony_ci		goto drop;
84398c2ecf20Sopenharmony_ci
84408c2ecf20Sopenharmony_ci	BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
84418c2ecf20Sopenharmony_ci
84428c2ecf20Sopenharmony_ci	switch (flags) {
84438c2ecf20Sopenharmony_ci	case ACL_START:
84448c2ecf20Sopenharmony_ci	case ACL_START_NO_FLUSH:
84458c2ecf20Sopenharmony_ci	case ACL_COMPLETE:
84468c2ecf20Sopenharmony_ci		if (conn->rx_len) {
84478c2ecf20Sopenharmony_ci			BT_ERR("Unexpected start frame (len %d)", skb->len);
84488c2ecf20Sopenharmony_ci			kfree_skb(conn->rx_skb);
84498c2ecf20Sopenharmony_ci			conn->rx_skb = NULL;
84508c2ecf20Sopenharmony_ci			conn->rx_len = 0;
84518c2ecf20Sopenharmony_ci			l2cap_conn_unreliable(conn, ECOMM);
84528c2ecf20Sopenharmony_ci		}
84538c2ecf20Sopenharmony_ci
84548c2ecf20Sopenharmony_ci		/* Start fragment always begin with Basic L2CAP header */
84558c2ecf20Sopenharmony_ci		if (skb->len < L2CAP_HDR_SIZE) {
84568c2ecf20Sopenharmony_ci			BT_ERR("Frame is too short (len %d)", skb->len);
84578c2ecf20Sopenharmony_ci			l2cap_conn_unreliable(conn, ECOMM);
84588c2ecf20Sopenharmony_ci			goto drop;
84598c2ecf20Sopenharmony_ci		}
84608c2ecf20Sopenharmony_ci
84618c2ecf20Sopenharmony_ci		hdr = (struct l2cap_hdr *) skb->data;
84628c2ecf20Sopenharmony_ci		len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
84638c2ecf20Sopenharmony_ci
84648c2ecf20Sopenharmony_ci		if (len == skb->len) {
84658c2ecf20Sopenharmony_ci			/* Complete frame received */
84668c2ecf20Sopenharmony_ci			l2cap_recv_frame(conn, skb);
84678c2ecf20Sopenharmony_ci			return;
84688c2ecf20Sopenharmony_ci		}
84698c2ecf20Sopenharmony_ci
84708c2ecf20Sopenharmony_ci		BT_DBG("Start: total len %d, frag len %d", len, skb->len);
84718c2ecf20Sopenharmony_ci
84728c2ecf20Sopenharmony_ci		if (skb->len > len) {
84738c2ecf20Sopenharmony_ci			BT_ERR("Frame is too long (len %d, expected len %d)",
84748c2ecf20Sopenharmony_ci			       skb->len, len);
84758c2ecf20Sopenharmony_ci			l2cap_conn_unreliable(conn, ECOMM);
84768c2ecf20Sopenharmony_ci			goto drop;
84778c2ecf20Sopenharmony_ci		}
84788c2ecf20Sopenharmony_ci
84798c2ecf20Sopenharmony_ci		/* Allocate skb for the complete frame (with header) */
84808c2ecf20Sopenharmony_ci		conn->rx_skb = bt_skb_alloc(len, GFP_KERNEL);
84818c2ecf20Sopenharmony_ci		if (!conn->rx_skb)
84828c2ecf20Sopenharmony_ci			goto drop;
84838c2ecf20Sopenharmony_ci
84848c2ecf20Sopenharmony_ci		skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
84858c2ecf20Sopenharmony_ci					  skb->len);
84868c2ecf20Sopenharmony_ci		conn->rx_len = len - skb->len;
84878c2ecf20Sopenharmony_ci		break;
84888c2ecf20Sopenharmony_ci
84898c2ecf20Sopenharmony_ci	case ACL_CONT:
84908c2ecf20Sopenharmony_ci		BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
84918c2ecf20Sopenharmony_ci
84928c2ecf20Sopenharmony_ci		if (!conn->rx_len) {
84938c2ecf20Sopenharmony_ci			BT_ERR("Unexpected continuation frame (len %d)", skb->len);
84948c2ecf20Sopenharmony_ci			l2cap_conn_unreliable(conn, ECOMM);
84958c2ecf20Sopenharmony_ci			goto drop;
84968c2ecf20Sopenharmony_ci		}
84978c2ecf20Sopenharmony_ci
84988c2ecf20Sopenharmony_ci		if (skb->len > conn->rx_len) {
84998c2ecf20Sopenharmony_ci			BT_ERR("Fragment is too long (len %d, expected %d)",
85008c2ecf20Sopenharmony_ci			       skb->len, conn->rx_len);
85018c2ecf20Sopenharmony_ci			kfree_skb(conn->rx_skb);
85028c2ecf20Sopenharmony_ci			conn->rx_skb = NULL;
85038c2ecf20Sopenharmony_ci			conn->rx_len = 0;
85048c2ecf20Sopenharmony_ci			l2cap_conn_unreliable(conn, ECOMM);
85058c2ecf20Sopenharmony_ci			goto drop;
85068c2ecf20Sopenharmony_ci		}
85078c2ecf20Sopenharmony_ci
85088c2ecf20Sopenharmony_ci		skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
85098c2ecf20Sopenharmony_ci					  skb->len);
85108c2ecf20Sopenharmony_ci		conn->rx_len -= skb->len;
85118c2ecf20Sopenharmony_ci
85128c2ecf20Sopenharmony_ci		if (!conn->rx_len) {
85138c2ecf20Sopenharmony_ci			/* Complete frame received. l2cap_recv_frame
85148c2ecf20Sopenharmony_ci			 * takes ownership of the skb so set the global
85158c2ecf20Sopenharmony_ci			 * rx_skb pointer to NULL first.
85168c2ecf20Sopenharmony_ci			 */
85178c2ecf20Sopenharmony_ci			struct sk_buff *rx_skb = conn->rx_skb;
85188c2ecf20Sopenharmony_ci			conn->rx_skb = NULL;
85198c2ecf20Sopenharmony_ci			l2cap_recv_frame(conn, rx_skb);
85208c2ecf20Sopenharmony_ci		}
85218c2ecf20Sopenharmony_ci		break;
85228c2ecf20Sopenharmony_ci	}
85238c2ecf20Sopenharmony_ci
85248c2ecf20Sopenharmony_cidrop:
85258c2ecf20Sopenharmony_ci	kfree_skb(skb);
85268c2ecf20Sopenharmony_ci}
85278c2ecf20Sopenharmony_ci
85288c2ecf20Sopenharmony_cistatic struct hci_cb l2cap_cb = {
85298c2ecf20Sopenharmony_ci	.name		= "L2CAP",
85308c2ecf20Sopenharmony_ci	.connect_cfm	= l2cap_connect_cfm,
85318c2ecf20Sopenharmony_ci	.disconn_cfm	= l2cap_disconn_cfm,
85328c2ecf20Sopenharmony_ci	.security_cfm	= l2cap_security_cfm,
85338c2ecf20Sopenharmony_ci};
85348c2ecf20Sopenharmony_ci
85358c2ecf20Sopenharmony_cistatic int l2cap_debugfs_show(struct seq_file *f, void *p)
85368c2ecf20Sopenharmony_ci{
85378c2ecf20Sopenharmony_ci	struct l2cap_chan *c;
85388c2ecf20Sopenharmony_ci
85398c2ecf20Sopenharmony_ci	read_lock(&chan_list_lock);
85408c2ecf20Sopenharmony_ci
85418c2ecf20Sopenharmony_ci	list_for_each_entry(c, &chan_list, global_l) {
85428c2ecf20Sopenharmony_ci		seq_printf(f, "%pMR (%u) %pMR (%u) %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
85438c2ecf20Sopenharmony_ci			   &c->src, c->src_type, &c->dst, c->dst_type,
85448c2ecf20Sopenharmony_ci			   c->state, __le16_to_cpu(c->psm),
85458c2ecf20Sopenharmony_ci			   c->scid, c->dcid, c->imtu, c->omtu,
85468c2ecf20Sopenharmony_ci			   c->sec_level, c->mode);
85478c2ecf20Sopenharmony_ci	}
85488c2ecf20Sopenharmony_ci
85498c2ecf20Sopenharmony_ci	read_unlock(&chan_list_lock);
85508c2ecf20Sopenharmony_ci
85518c2ecf20Sopenharmony_ci	return 0;
85528c2ecf20Sopenharmony_ci}
85538c2ecf20Sopenharmony_ci
85548c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(l2cap_debugfs);
85558c2ecf20Sopenharmony_ci
85568c2ecf20Sopenharmony_cistatic struct dentry *l2cap_debugfs;
85578c2ecf20Sopenharmony_ci
85588c2ecf20Sopenharmony_ciint __init l2cap_init(void)
85598c2ecf20Sopenharmony_ci{
85608c2ecf20Sopenharmony_ci	int err;
85618c2ecf20Sopenharmony_ci
85628c2ecf20Sopenharmony_ci	err = l2cap_init_sockets();
85638c2ecf20Sopenharmony_ci	if (err < 0)
85648c2ecf20Sopenharmony_ci		return err;
85658c2ecf20Sopenharmony_ci
85668c2ecf20Sopenharmony_ci	hci_register_cb(&l2cap_cb);
85678c2ecf20Sopenharmony_ci
85688c2ecf20Sopenharmony_ci	if (IS_ERR_OR_NULL(bt_debugfs))
85698c2ecf20Sopenharmony_ci		return 0;
85708c2ecf20Sopenharmony_ci
85718c2ecf20Sopenharmony_ci	l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs,
85728c2ecf20Sopenharmony_ci					    NULL, &l2cap_debugfs_fops);
85738c2ecf20Sopenharmony_ci
85748c2ecf20Sopenharmony_ci	return 0;
85758c2ecf20Sopenharmony_ci}
85768c2ecf20Sopenharmony_ci
85778c2ecf20Sopenharmony_civoid l2cap_exit(void)
85788c2ecf20Sopenharmony_ci{
85798c2ecf20Sopenharmony_ci	debugfs_remove(l2cap_debugfs);
85808c2ecf20Sopenharmony_ci	hci_unregister_cb(&l2cap_cb);
85818c2ecf20Sopenharmony_ci	l2cap_cleanup_sockets();
85828c2ecf20Sopenharmony_ci}
85838c2ecf20Sopenharmony_ci
85848c2ecf20Sopenharmony_cimodule_param(disable_ertm, bool, 0644);
85858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
85868c2ecf20Sopenharmony_ci
85878c2ecf20Sopenharmony_cimodule_param(enable_ecred, bool, 0644);
85888c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_ecred, "Enable enhanced credit flow control mode");
8589