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