10a708f8fSGustavo F. Padovan /* 20a708f8fSGustavo F. Padovan BlueZ - Bluetooth protocol stack for Linux 30a708f8fSGustavo F. Padovan Copyright (C) 2000-2001 Qualcomm Incorporated 40a708f8fSGustavo F. Padovan Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org> 50a708f8fSGustavo F. Padovan Copyright (C) 2010 Google Inc. 6590051deSGustavo F. Padovan Copyright (C) 2011 ProFUSION Embedded Systems 70a708f8fSGustavo F. Padovan 80a708f8fSGustavo F. Padovan Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> 90a708f8fSGustavo F. Padovan 100a708f8fSGustavo F. Padovan This program is free software; you can redistribute it and/or modify 110a708f8fSGustavo F. Padovan it under the terms of the GNU General Public License version 2 as 120a708f8fSGustavo F. Padovan published by the Free Software Foundation; 130a708f8fSGustavo F. Padovan 140a708f8fSGustavo F. Padovan THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 150a708f8fSGustavo F. Padovan OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 160a708f8fSGustavo F. Padovan FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 170a708f8fSGustavo F. Padovan IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY 180a708f8fSGustavo F. Padovan CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 190a708f8fSGustavo F. Padovan WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 200a708f8fSGustavo F. Padovan ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 210a708f8fSGustavo F. Padovan OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 220a708f8fSGustavo F. Padovan 230a708f8fSGustavo F. Padovan ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 240a708f8fSGustavo F. Padovan COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 250a708f8fSGustavo F. Padovan SOFTWARE IS DISCLAIMED. 260a708f8fSGustavo F. Padovan */ 270a708f8fSGustavo F. Padovan 28bb58f747SGustavo F. Padovan /* Bluetooth L2CAP core. */ 290a708f8fSGustavo F. Padovan 300a708f8fSGustavo F. Padovan #include <linux/module.h> 310a708f8fSGustavo F. Padovan 320a708f8fSGustavo F. Padovan #include <linux/types.h> 330a708f8fSGustavo F. Padovan #include <linux/capability.h> 340a708f8fSGustavo F. Padovan #include <linux/errno.h> 350a708f8fSGustavo F. Padovan #include <linux/kernel.h> 360a708f8fSGustavo F. Padovan #include <linux/sched.h> 370a708f8fSGustavo F. Padovan #include <linux/slab.h> 380a708f8fSGustavo F. Padovan #include <linux/poll.h> 390a708f8fSGustavo F. Padovan #include <linux/fcntl.h> 400a708f8fSGustavo F. Padovan #include <linux/init.h> 410a708f8fSGustavo F. Padovan #include <linux/interrupt.h> 420a708f8fSGustavo F. Padovan #include <linux/socket.h> 430a708f8fSGustavo F. Padovan #include <linux/skbuff.h> 440a708f8fSGustavo F. Padovan #include <linux/list.h> 450a708f8fSGustavo F. Padovan #include <linux/device.h> 460a708f8fSGustavo F. Padovan #include <linux/debugfs.h> 470a708f8fSGustavo F. Padovan #include <linux/seq_file.h> 480a708f8fSGustavo F. Padovan #include <linux/uaccess.h> 490a708f8fSGustavo F. Padovan #include <linux/crc16.h> 500a708f8fSGustavo F. Padovan #include <net/sock.h> 510a708f8fSGustavo F. Padovan 520a708f8fSGustavo F. Padovan #include <asm/unaligned.h> 530a708f8fSGustavo F. Padovan 540a708f8fSGustavo F. Padovan #include <net/bluetooth/bluetooth.h> 550a708f8fSGustavo F. Padovan #include <net/bluetooth/hci_core.h> 560a708f8fSGustavo F. Padovan #include <net/bluetooth/l2cap.h> 57b501d6a1SAnderson Briglia #include <net/bluetooth/smp.h> 580a708f8fSGustavo F. Padovan 59eb939922SRusty Russell bool disable_ertm; 600a708f8fSGustavo F. Padovan 610a708f8fSGustavo F. Padovan static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN; 6250a147cdSMat Martineau static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, }; 630a708f8fSGustavo F. Padovan 64b5ad8b7fSJohannes Berg static LIST_HEAD(chan_list); 65b5ad8b7fSJohannes Berg static DEFINE_RWLOCK(chan_list_lock); 660a708f8fSGustavo F. Padovan 670a708f8fSGustavo F. Padovan static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, 680a708f8fSGustavo F. Padovan u8 code, u8 ident, u16 dlen, void *data); 694519de9aSGustavo F. Padovan static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, 704519de9aSGustavo F. Padovan void *data); 71710f9b0aSGustavo F. Padovan static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); 724519de9aSGustavo F. Padovan static void l2cap_send_disconn_req(struct l2cap_conn *conn, 734519de9aSGustavo F. Padovan struct l2cap_chan *chan, int err); 740a708f8fSGustavo F. Padovan 750a708f8fSGustavo F. Padovan /* ---- L2CAP channels ---- */ 7671ba0e56SGustavo F. Padovan 77baa7e1faSGustavo F. Padovan static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) 780a708f8fSGustavo F. Padovan { 793df91ea2SAndrei Emeltchenko struct l2cap_chan *c; 80baa7e1faSGustavo F. Padovan 813df91ea2SAndrei Emeltchenko list_for_each_entry(c, &conn->chan_l, list) { 823df91ea2SAndrei Emeltchenko if (c->dcid == cid) 833df91ea2SAndrei Emeltchenko return c; 840a708f8fSGustavo F. Padovan } 853df91ea2SAndrei Emeltchenko return NULL; 86baa7e1faSGustavo F. Padovan } 870a708f8fSGustavo F. Padovan 88baa7e1faSGustavo F. Padovan static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) 890a708f8fSGustavo F. Padovan { 903df91ea2SAndrei Emeltchenko struct l2cap_chan *c; 91baa7e1faSGustavo F. Padovan 923df91ea2SAndrei Emeltchenko list_for_each_entry(c, &conn->chan_l, list) { 933df91ea2SAndrei Emeltchenko if (c->scid == cid) 943df91ea2SAndrei Emeltchenko return c; 950a708f8fSGustavo F. Padovan } 963df91ea2SAndrei Emeltchenko return NULL; 97baa7e1faSGustavo F. Padovan } 980a708f8fSGustavo F. Padovan 990a708f8fSGustavo F. Padovan /* Find channel with given SCID. 1000a708f8fSGustavo F. Padovan * Returns locked socket */ 101baa7e1faSGustavo F. Padovan static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) 1020a708f8fSGustavo F. Padovan { 10348454079SGustavo F. Padovan struct l2cap_chan *c; 104baa7e1faSGustavo F. Padovan 1053df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 106baa7e1faSGustavo F. Padovan c = __l2cap_get_chan_by_scid(conn, cid); 1073df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 1083df91ea2SAndrei Emeltchenko 10948454079SGustavo F. Padovan return c; 1100a708f8fSGustavo F. Padovan } 1110a708f8fSGustavo F. Padovan 112baa7e1faSGustavo F. Padovan static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) 1130a708f8fSGustavo F. Padovan { 1143df91ea2SAndrei Emeltchenko struct l2cap_chan *c; 115baa7e1faSGustavo F. Padovan 1163df91ea2SAndrei Emeltchenko list_for_each_entry(c, &conn->chan_l, list) { 1173df91ea2SAndrei Emeltchenko if (c->ident == ident) 1183df91ea2SAndrei Emeltchenko return c; 1190a708f8fSGustavo F. Padovan } 1203df91ea2SAndrei Emeltchenko return NULL; 121baa7e1faSGustavo F. Padovan } 1220a708f8fSGustavo F. Padovan 12323691d75SGustavo F. Padovan static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) 1249e4425ffSGustavo F. Padovan { 12523691d75SGustavo F. Padovan struct l2cap_chan *c; 1269e4425ffSGustavo F. Padovan 12723691d75SGustavo F. Padovan list_for_each_entry(c, &chan_list, global_l) { 12823691d75SGustavo F. Padovan if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src)) 12923691d75SGustavo F. Padovan return c; 1309e4425ffSGustavo F. Padovan } 131250938cbSSzymon Janc return NULL; 132250938cbSSzymon Janc } 1339e4425ffSGustavo F. Padovan 1349e4425ffSGustavo F. Padovan int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) 1359e4425ffSGustavo F. Padovan { 13673b2ec18SGustavo F. Padovan int err; 13773b2ec18SGustavo F. Padovan 138333055f2SGustavo F. Padovan write_lock(&chan_list_lock); 1399e4425ffSGustavo F. Padovan 14023691d75SGustavo F. Padovan if (psm && __l2cap_global_chan_by_addr(psm, src)) { 14173b2ec18SGustavo F. Padovan err = -EADDRINUSE; 14273b2ec18SGustavo F. Padovan goto done; 1439e4425ffSGustavo F. Padovan } 1449e4425ffSGustavo F. Padovan 14573b2ec18SGustavo F. Padovan if (psm) { 1469e4425ffSGustavo F. Padovan chan->psm = psm; 1479e4425ffSGustavo F. Padovan chan->sport = psm; 14873b2ec18SGustavo F. Padovan err = 0; 14973b2ec18SGustavo F. Padovan } else { 15073b2ec18SGustavo F. Padovan u16 p; 1519e4425ffSGustavo F. Padovan 15273b2ec18SGustavo F. Padovan err = -EINVAL; 15373b2ec18SGustavo F. Padovan for (p = 0x1001; p < 0x1100; p += 2) 15423691d75SGustavo F. Padovan if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) { 15573b2ec18SGustavo F. Padovan chan->psm = cpu_to_le16(p); 15673b2ec18SGustavo F. Padovan chan->sport = cpu_to_le16(p); 15773b2ec18SGustavo F. Padovan err = 0; 15873b2ec18SGustavo F. Padovan break; 15973b2ec18SGustavo F. Padovan } 16073b2ec18SGustavo F. Padovan } 16173b2ec18SGustavo F. Padovan 16273b2ec18SGustavo F. Padovan done: 163333055f2SGustavo F. Padovan write_unlock(&chan_list_lock); 16473b2ec18SGustavo F. Padovan return err; 1659e4425ffSGustavo F. Padovan } 1669e4425ffSGustavo F. Padovan 1679e4425ffSGustavo F. Padovan int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) 1689e4425ffSGustavo F. Padovan { 169333055f2SGustavo F. Padovan write_lock(&chan_list_lock); 1709e4425ffSGustavo F. Padovan 1719e4425ffSGustavo F. Padovan chan->scid = scid; 1729e4425ffSGustavo F. Padovan 173333055f2SGustavo F. Padovan write_unlock(&chan_list_lock); 1749e4425ffSGustavo F. Padovan 1759e4425ffSGustavo F. Padovan return 0; 1769e4425ffSGustavo F. Padovan } 1779e4425ffSGustavo F. Padovan 178baa7e1faSGustavo F. Padovan static u16 l2cap_alloc_cid(struct l2cap_conn *conn) 1790a708f8fSGustavo F. Padovan { 1800a708f8fSGustavo F. Padovan u16 cid = L2CAP_CID_DYN_START; 1810a708f8fSGustavo F. Padovan 1820a708f8fSGustavo F. Padovan for (; cid < L2CAP_CID_DYN_END; cid++) { 183baa7e1faSGustavo F. Padovan if (!__l2cap_get_chan_by_scid(conn, cid)) 1840a708f8fSGustavo F. Padovan return cid; 1850a708f8fSGustavo F. Padovan } 1860a708f8fSGustavo F. Padovan 1870a708f8fSGustavo F. Padovan return 0; 1880a708f8fSGustavo F. Padovan } 1890a708f8fSGustavo F. Padovan 1900e587be7SAndrei Emeltchenko static void __l2cap_state_change(struct l2cap_chan *chan, int state) 19189bc500eSGustavo F. Padovan { 19242d2d87cSAndrei Emeltchenko BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state), 193badaaa00SGustavo F. Padovan state_to_string(state)); 194badaaa00SGustavo F. Padovan 19589bc500eSGustavo F. Padovan chan->state = state; 19689bc500eSGustavo F. Padovan chan->ops->state_change(chan->data, state); 19789bc500eSGustavo F. Padovan } 19889bc500eSGustavo F. Padovan 1990e587be7SAndrei Emeltchenko static void l2cap_state_change(struct l2cap_chan *chan, int state) 2000e587be7SAndrei Emeltchenko { 2010e587be7SAndrei Emeltchenko struct sock *sk = chan->sk; 2020e587be7SAndrei Emeltchenko 2030e587be7SAndrei Emeltchenko lock_sock(sk); 2040e587be7SAndrei Emeltchenko __l2cap_state_change(chan, state); 2050e587be7SAndrei Emeltchenko release_sock(sk); 2060e587be7SAndrei Emeltchenko } 2070e587be7SAndrei Emeltchenko 2082e0052e4SAndrei Emeltchenko static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err) 2092e0052e4SAndrei Emeltchenko { 2102e0052e4SAndrei Emeltchenko struct sock *sk = chan->sk; 2112e0052e4SAndrei Emeltchenko 2122e0052e4SAndrei Emeltchenko sk->sk_err = err; 2132e0052e4SAndrei Emeltchenko } 2142e0052e4SAndrei Emeltchenko 2152e0052e4SAndrei Emeltchenko static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err) 2162e0052e4SAndrei Emeltchenko { 2172e0052e4SAndrei Emeltchenko struct sock *sk = chan->sk; 2182e0052e4SAndrei Emeltchenko 2192e0052e4SAndrei Emeltchenko lock_sock(sk); 2202e0052e4SAndrei Emeltchenko __l2cap_chan_set_err(chan, err); 2212e0052e4SAndrei Emeltchenko release_sock(sk); 2222e0052e4SAndrei Emeltchenko } 2232e0052e4SAndrei Emeltchenko 2243c588192SMat Martineau /* ---- L2CAP sequence number lists ---- */ 2253c588192SMat Martineau 2263c588192SMat Martineau /* For ERTM, ordered lists of sequence numbers must be tracked for 2273c588192SMat Martineau * SREJ requests that are received and for frames that are to be 2283c588192SMat Martineau * retransmitted. These seq_list functions implement a singly-linked 2293c588192SMat Martineau * list in an array, where membership in the list can also be checked 2303c588192SMat Martineau * in constant time. Items can also be added to the tail of the list 2313c588192SMat Martineau * and removed from the head in constant time, without further memory 2323c588192SMat Martineau * allocs or frees. 2333c588192SMat Martineau */ 2343c588192SMat Martineau 2353c588192SMat Martineau static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size) 2363c588192SMat Martineau { 2373c588192SMat Martineau size_t alloc_size, i; 2383c588192SMat Martineau 2393c588192SMat Martineau /* Allocated size is a power of 2 to map sequence numbers 2403c588192SMat Martineau * (which may be up to 14 bits) in to a smaller array that is 2413c588192SMat Martineau * sized for the negotiated ERTM transmit windows. 2423c588192SMat Martineau */ 2433c588192SMat Martineau alloc_size = roundup_pow_of_two(size); 2443c588192SMat Martineau 2453c588192SMat Martineau seq_list->list = kmalloc(sizeof(u16) * alloc_size, GFP_KERNEL); 2463c588192SMat Martineau if (!seq_list->list) 2473c588192SMat Martineau return -ENOMEM; 2483c588192SMat Martineau 2493c588192SMat Martineau seq_list->mask = alloc_size - 1; 2503c588192SMat Martineau seq_list->head = L2CAP_SEQ_LIST_CLEAR; 2513c588192SMat Martineau seq_list->tail = L2CAP_SEQ_LIST_CLEAR; 2523c588192SMat Martineau for (i = 0; i < alloc_size; i++) 2533c588192SMat Martineau seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; 2543c588192SMat Martineau 2553c588192SMat Martineau return 0; 2563c588192SMat Martineau } 2573c588192SMat Martineau 2583c588192SMat Martineau static inline void l2cap_seq_list_free(struct l2cap_seq_list *seq_list) 2593c588192SMat Martineau { 2603c588192SMat Martineau kfree(seq_list->list); 2613c588192SMat Martineau } 2623c588192SMat Martineau 2633c588192SMat Martineau static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list, 2643c588192SMat Martineau u16 seq) 2653c588192SMat Martineau { 2663c588192SMat Martineau /* Constant-time check for list membership */ 2673c588192SMat Martineau return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR; 2683c588192SMat Martineau } 2693c588192SMat Martineau 2703c588192SMat Martineau static u16 l2cap_seq_list_remove(struct l2cap_seq_list *seq_list, u16 seq) 2713c588192SMat Martineau { 2723c588192SMat Martineau u16 mask = seq_list->mask; 2733c588192SMat Martineau 2743c588192SMat Martineau if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) { 2753c588192SMat Martineau /* In case someone tries to pop the head of an empty list */ 2763c588192SMat Martineau return L2CAP_SEQ_LIST_CLEAR; 2773c588192SMat Martineau } else if (seq_list->head == seq) { 2783c588192SMat Martineau /* Head can be removed in constant time */ 2793c588192SMat Martineau seq_list->head = seq_list->list[seq & mask]; 2803c588192SMat Martineau seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; 2813c588192SMat Martineau 2823c588192SMat Martineau if (seq_list->head == L2CAP_SEQ_LIST_TAIL) { 2833c588192SMat Martineau seq_list->head = L2CAP_SEQ_LIST_CLEAR; 2843c588192SMat Martineau seq_list->tail = L2CAP_SEQ_LIST_CLEAR; 2853c588192SMat Martineau } 2863c588192SMat Martineau } else { 2873c588192SMat Martineau /* Walk the list to find the sequence number */ 2883c588192SMat Martineau u16 prev = seq_list->head; 2893c588192SMat Martineau while (seq_list->list[prev & mask] != seq) { 2903c588192SMat Martineau prev = seq_list->list[prev & mask]; 2913c588192SMat Martineau if (prev == L2CAP_SEQ_LIST_TAIL) 2923c588192SMat Martineau return L2CAP_SEQ_LIST_CLEAR; 2933c588192SMat Martineau } 2943c588192SMat Martineau 2953c588192SMat Martineau /* Unlink the number from the list and clear it */ 2963c588192SMat Martineau seq_list->list[prev & mask] = seq_list->list[seq & mask]; 2973c588192SMat Martineau seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; 2983c588192SMat Martineau if (seq_list->tail == seq) 2993c588192SMat Martineau seq_list->tail = prev; 3003c588192SMat Martineau } 3013c588192SMat Martineau return seq; 3023c588192SMat Martineau } 3033c588192SMat Martineau 3043c588192SMat Martineau static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list) 3053c588192SMat Martineau { 3063c588192SMat Martineau /* Remove the head in constant time */ 3073c588192SMat Martineau return l2cap_seq_list_remove(seq_list, seq_list->head); 3083c588192SMat Martineau } 3093c588192SMat Martineau 3103c588192SMat Martineau static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list) 3113c588192SMat Martineau { 3123c588192SMat Martineau if (seq_list->head != L2CAP_SEQ_LIST_CLEAR) { 3133c588192SMat Martineau u16 i; 3143c588192SMat Martineau for (i = 0; i <= seq_list->mask; i++) 3153c588192SMat Martineau seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; 3163c588192SMat Martineau 3173c588192SMat Martineau seq_list->head = L2CAP_SEQ_LIST_CLEAR; 3183c588192SMat Martineau seq_list->tail = L2CAP_SEQ_LIST_CLEAR; 3193c588192SMat Martineau } 3203c588192SMat Martineau } 3213c588192SMat Martineau 3223c588192SMat Martineau static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq) 3233c588192SMat Martineau { 3243c588192SMat Martineau u16 mask = seq_list->mask; 3253c588192SMat Martineau 3263c588192SMat Martineau /* All appends happen in constant time */ 3273c588192SMat Martineau 3283c588192SMat Martineau if (seq_list->list[seq & mask] == L2CAP_SEQ_LIST_CLEAR) { 3293c588192SMat Martineau if (seq_list->tail == L2CAP_SEQ_LIST_CLEAR) 3303c588192SMat Martineau seq_list->head = seq; 3313c588192SMat Martineau else 3323c588192SMat Martineau seq_list->list[seq_list->tail & mask] = seq; 3333c588192SMat Martineau 3343c588192SMat Martineau seq_list->tail = seq; 3353c588192SMat Martineau seq_list->list[seq & mask] = L2CAP_SEQ_LIST_TAIL; 3363c588192SMat Martineau } 3373c588192SMat Martineau } 3383c588192SMat Martineau 339721c4181SGustavo F. Padovan static void l2cap_chan_timeout(struct work_struct *work) 340ab07801dSGustavo F. Padovan { 341721c4181SGustavo F. Padovan struct l2cap_chan *chan = container_of(work, struct l2cap_chan, 342721c4181SGustavo F. Padovan chan_timer.work); 3433df91ea2SAndrei Emeltchenko struct l2cap_conn *conn = chan->conn; 344ab07801dSGustavo F. Padovan int reason; 345ab07801dSGustavo F. Padovan 346e05dcc32SAndrei Emeltchenko BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); 347ab07801dSGustavo F. Padovan 3483df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 3496be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 350ab07801dSGustavo F. Padovan 35189bc500eSGustavo F. Padovan if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG) 352ab07801dSGustavo F. Padovan reason = ECONNREFUSED; 35389bc500eSGustavo F. Padovan else if (chan->state == BT_CONNECT && 354ab07801dSGustavo F. Padovan chan->sec_level != BT_SECURITY_SDP) 355ab07801dSGustavo F. Padovan reason = ECONNREFUSED; 356ab07801dSGustavo F. Padovan else 357ab07801dSGustavo F. Padovan reason = ETIMEDOUT; 358ab07801dSGustavo F. Padovan 3590f852724SGustavo F. Padovan l2cap_chan_close(chan, reason); 360ab07801dSGustavo F. Padovan 3616be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 362ab07801dSGustavo F. Padovan 363ba3bd0eeSGustavo F. Padovan chan->ops->close(chan->data); 3643df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 3653df91ea2SAndrei Emeltchenko 366371fd835SUlisses Furquim l2cap_chan_put(chan); 367ab07801dSGustavo F. Padovan } 368ab07801dSGustavo F. Padovan 369eef1d9b6SGustavo Padovan struct l2cap_chan *l2cap_chan_create(void) 3700a708f8fSGustavo F. Padovan { 37148454079SGustavo F. Padovan struct l2cap_chan *chan; 3720a708f8fSGustavo F. Padovan 37348454079SGustavo F. Padovan chan = kzalloc(sizeof(*chan), GFP_ATOMIC); 37448454079SGustavo F. Padovan if (!chan) 37548454079SGustavo F. Padovan return NULL; 3760a708f8fSGustavo F. Padovan 377c03b355eSAndrei Emeltchenko mutex_init(&chan->lock); 378c03b355eSAndrei Emeltchenko 379333055f2SGustavo F. Padovan write_lock(&chan_list_lock); 38023691d75SGustavo F. Padovan list_add(&chan->global_l, &chan_list); 381333055f2SGustavo F. Padovan write_unlock(&chan_list_lock); 38223691d75SGustavo F. Padovan 383721c4181SGustavo F. Padovan INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout); 384ab07801dSGustavo F. Padovan 38589bc500eSGustavo F. Padovan chan->state = BT_OPEN; 38689bc500eSGustavo F. Padovan 38771ba0e56SGustavo F. Padovan atomic_set(&chan->refcnt, 1); 38871ba0e56SGustavo F. Padovan 389eef1d9b6SGustavo Padovan BT_DBG("chan %p", chan); 390abc545b8SSzymon Janc 39148454079SGustavo F. Padovan return chan; 3920a708f8fSGustavo F. Padovan } 3930a708f8fSGustavo F. Padovan 39423691d75SGustavo F. Padovan void l2cap_chan_destroy(struct l2cap_chan *chan) 3956ff5abbfSGustavo F. Padovan { 396333055f2SGustavo F. Padovan write_lock(&chan_list_lock); 39723691d75SGustavo F. Padovan list_del(&chan->global_l); 398333055f2SGustavo F. Padovan write_unlock(&chan_list_lock); 39923691d75SGustavo F. Padovan 400371fd835SUlisses Furquim l2cap_chan_put(chan); 4016ff5abbfSGustavo F. Padovan } 4026ff5abbfSGustavo F. Padovan 403bd4b1653SAndrei Emeltchenko void l2cap_chan_set_defaults(struct l2cap_chan *chan) 404bd4b1653SAndrei Emeltchenko { 405bd4b1653SAndrei Emeltchenko chan->fcs = L2CAP_FCS_CRC16; 406bd4b1653SAndrei Emeltchenko chan->max_tx = L2CAP_DEFAULT_MAX_TX; 407bd4b1653SAndrei Emeltchenko chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; 408bd4b1653SAndrei Emeltchenko chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; 409bd4b1653SAndrei Emeltchenko chan->sec_level = BT_SECURITY_LOW; 410bd4b1653SAndrei Emeltchenko 411bd4b1653SAndrei Emeltchenko set_bit(FLAG_FORCE_ACTIVE, &chan->flags); 412bd4b1653SAndrei Emeltchenko } 413bd4b1653SAndrei Emeltchenko 41414a28491SAndrei Emeltchenko static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) 4150a708f8fSGustavo F. Padovan { 4160a708f8fSGustavo F. Padovan BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, 417097db76cSAndrei Emeltchenko __le16_to_cpu(chan->psm), chan->dcid); 4180a708f8fSGustavo F. Padovan 4199f5a0d7bSAndrei Emeltchenko conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; 4200a708f8fSGustavo F. Padovan 4218c1d787bSGustavo F. Padovan chan->conn = conn; 4220a708f8fSGustavo F. Padovan 4235491120eSAndrei Emeltchenko switch (chan->chan_type) { 4245491120eSAndrei Emeltchenko case L2CAP_CHAN_CONN_ORIENTED: 425b62f328bSVille Tervo if (conn->hcon->type == LE_LINK) { 426b62f328bSVille Tervo /* LE connection */ 4270c1bc5c6SGustavo F. Padovan chan->omtu = L2CAP_LE_DEFAULT_MTU; 428fe4128e0SGustavo F. Padovan chan->scid = L2CAP_CID_LE_DATA; 429fe4128e0SGustavo F. Padovan chan->dcid = L2CAP_CID_LE_DATA; 430b62f328bSVille Tervo } else { 4310a708f8fSGustavo F. Padovan /* Alloc CID for connection-oriented socket */ 432fe4128e0SGustavo F. Padovan chan->scid = l2cap_alloc_cid(conn); 4330c1bc5c6SGustavo F. Padovan chan->omtu = L2CAP_DEFAULT_MTU; 434b62f328bSVille Tervo } 4355491120eSAndrei Emeltchenko break; 4365491120eSAndrei Emeltchenko 4375491120eSAndrei Emeltchenko case L2CAP_CHAN_CONN_LESS: 4380a708f8fSGustavo F. Padovan /* Connectionless socket */ 439fe4128e0SGustavo F. Padovan chan->scid = L2CAP_CID_CONN_LESS; 440fe4128e0SGustavo F. Padovan chan->dcid = L2CAP_CID_CONN_LESS; 4410c1bc5c6SGustavo F. Padovan chan->omtu = L2CAP_DEFAULT_MTU; 4425491120eSAndrei Emeltchenko break; 4435491120eSAndrei Emeltchenko 4445491120eSAndrei Emeltchenko default: 4450a708f8fSGustavo F. Padovan /* Raw socket can send/recv signalling messages only */ 446fe4128e0SGustavo F. Padovan chan->scid = L2CAP_CID_SIGNALING; 447fe4128e0SGustavo F. Padovan chan->dcid = L2CAP_CID_SIGNALING; 4480c1bc5c6SGustavo F. Padovan chan->omtu = L2CAP_DEFAULT_MTU; 4490a708f8fSGustavo F. Padovan } 4500a708f8fSGustavo F. Padovan 4518f7975b1SAndrei Emeltchenko chan->local_id = L2CAP_BESTEFFORT_ID; 4528f7975b1SAndrei Emeltchenko chan->local_stype = L2CAP_SERV_BESTEFFORT; 4538f7975b1SAndrei Emeltchenko chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE; 4548f7975b1SAndrei Emeltchenko chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME; 4558f7975b1SAndrei Emeltchenko chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT; 4568f7975b1SAndrei Emeltchenko chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO; 4578f7975b1SAndrei Emeltchenko 458371fd835SUlisses Furquim l2cap_chan_hold(chan); 459baa7e1faSGustavo F. Padovan 4603df91ea2SAndrei Emeltchenko list_add(&chan->list, &conn->chan_l); 461643162a8SAndrei Emeltchenko } 462643162a8SAndrei Emeltchenko 46314a28491SAndrei Emeltchenko static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) 464643162a8SAndrei Emeltchenko { 465643162a8SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 466643162a8SAndrei Emeltchenko __l2cap_chan_add(conn, chan); 4673df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 4680a708f8fSGustavo F. Padovan } 4690a708f8fSGustavo F. Padovan 4704519de9aSGustavo F. Padovan static void l2cap_chan_del(struct l2cap_chan *chan, int err) 4710a708f8fSGustavo F. Padovan { 47248454079SGustavo F. Padovan struct sock *sk = chan->sk; 4738c1d787bSGustavo F. Padovan struct l2cap_conn *conn = chan->conn; 4740a708f8fSGustavo F. Padovan struct sock *parent = bt_sk(sk)->parent; 4750a708f8fSGustavo F. Padovan 476c9b66675SGustavo F. Padovan __clear_chan_timer(chan); 4770a708f8fSGustavo F. Padovan 47849208c9cSGustavo F. Padovan BT_DBG("chan %p, conn %p, err %d", chan, conn, err); 4790a708f8fSGustavo F. Padovan 4800a708f8fSGustavo F. Padovan if (conn) { 481baa7e1faSGustavo F. Padovan /* Delete from channel list */ 4823df91ea2SAndrei Emeltchenko list_del(&chan->list); 4833d57dc68SGustavo F. Padovan 484371fd835SUlisses Furquim l2cap_chan_put(chan); 485baa7e1faSGustavo F. Padovan 4868c1d787bSGustavo F. Padovan chan->conn = NULL; 4870a708f8fSGustavo F. Padovan hci_conn_put(conn->hcon); 4880a708f8fSGustavo F. Padovan } 4890a708f8fSGustavo F. Padovan 4906be36555SAndrei Emeltchenko lock_sock(sk); 4916be36555SAndrei Emeltchenko 4920e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_CLOSED); 4930a708f8fSGustavo F. Padovan sock_set_flag(sk, SOCK_ZAPPED); 4940a708f8fSGustavo F. Padovan 4950a708f8fSGustavo F. Padovan if (err) 4962e0052e4SAndrei Emeltchenko __l2cap_chan_set_err(chan, err); 4970a708f8fSGustavo F. Padovan 4980a708f8fSGustavo F. Padovan if (parent) { 4990a708f8fSGustavo F. Padovan bt_accept_unlink(sk); 5000a708f8fSGustavo F. Padovan parent->sk_data_ready(parent, 0); 5010a708f8fSGustavo F. Padovan } else 5020a708f8fSGustavo F. Padovan sk->sk_state_change(sk); 5030a708f8fSGustavo F. Padovan 5046be36555SAndrei Emeltchenko release_sock(sk); 5056be36555SAndrei Emeltchenko 506c1360a1cSGustavo F. Padovan if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) && 507c1360a1cSGustavo F. Padovan test_bit(CONF_INPUT_DONE, &chan->conf_state))) 5086ff5abbfSGustavo F. Padovan return; 5092ead70b8SGustavo F. Padovan 51058d35f87SGustavo F. Padovan skb_queue_purge(&chan->tx_q); 5110a708f8fSGustavo F. Padovan 5120c1bc5c6SGustavo F. Padovan if (chan->mode == L2CAP_MODE_ERTM) { 5130a708f8fSGustavo F. Padovan struct srej_list *l, *tmp; 5140a708f8fSGustavo F. Padovan 5151a09bcb9SGustavo F. Padovan __clear_retrans_timer(chan); 5161a09bcb9SGustavo F. Padovan __clear_monitor_timer(chan); 5171a09bcb9SGustavo F. Padovan __clear_ack_timer(chan); 5180a708f8fSGustavo F. Padovan 519f1c6775bSGustavo F. Padovan skb_queue_purge(&chan->srej_q); 5200a708f8fSGustavo F. Padovan 5213c588192SMat Martineau l2cap_seq_list_free(&chan->srej_list); 5223c588192SMat Martineau l2cap_seq_list_free(&chan->retrans_list); 52339d5a3eeSGustavo F. Padovan list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { 5240a708f8fSGustavo F. Padovan list_del(&l->list); 5250a708f8fSGustavo F. Padovan kfree(l); 5260a708f8fSGustavo F. Padovan } 5270a708f8fSGustavo F. Padovan } 5280a708f8fSGustavo F. Padovan } 5290a708f8fSGustavo F. Padovan 5304519de9aSGustavo F. Padovan static void l2cap_chan_cleanup_listen(struct sock *parent) 5314519de9aSGustavo F. Padovan { 5324519de9aSGustavo F. Padovan struct sock *sk; 5334519de9aSGustavo F. Padovan 5344519de9aSGustavo F. Padovan BT_DBG("parent %p", parent); 5354519de9aSGustavo F. Padovan 5364519de9aSGustavo F. Padovan /* Close not yet accepted channels */ 5370f852724SGustavo F. Padovan while ((sk = bt_accept_dequeue(parent, NULL))) { 538ba3bd0eeSGustavo F. Padovan struct l2cap_chan *chan = l2cap_pi(sk)->chan; 5393df91ea2SAndrei Emeltchenko 5406be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 541c9b66675SGustavo F. Padovan __clear_chan_timer(chan); 542ba3bd0eeSGustavo F. Padovan l2cap_chan_close(chan, ECONNRESET); 5436be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 5443df91ea2SAndrei Emeltchenko 545ba3bd0eeSGustavo F. Padovan chan->ops->close(chan->data); 5460f852724SGustavo F. Padovan } 5474519de9aSGustavo F. Padovan } 5484519de9aSGustavo F. Padovan 5490f852724SGustavo F. Padovan void l2cap_chan_close(struct l2cap_chan *chan, int reason) 5504519de9aSGustavo F. Padovan { 5514519de9aSGustavo F. Padovan struct l2cap_conn *conn = chan->conn; 5524519de9aSGustavo F. Padovan struct sock *sk = chan->sk; 5534519de9aSGustavo F. Padovan 554e05dcc32SAndrei Emeltchenko BT_DBG("chan %p state %s sk %p", chan, 555e05dcc32SAndrei Emeltchenko state_to_string(chan->state), sk); 5564519de9aSGustavo F. Padovan 55789bc500eSGustavo F. Padovan switch (chan->state) { 5584519de9aSGustavo F. Padovan case BT_LISTEN: 5596be36555SAndrei Emeltchenko lock_sock(sk); 5604519de9aSGustavo F. Padovan l2cap_chan_cleanup_listen(sk); 56189bc500eSGustavo F. Padovan 5620e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_CLOSED); 56389bc500eSGustavo F. Padovan sock_set_flag(sk, SOCK_ZAPPED); 5646be36555SAndrei Emeltchenko release_sock(sk); 5654519de9aSGustavo F. Padovan break; 5664519de9aSGustavo F. Padovan 5674519de9aSGustavo F. Padovan case BT_CONNECTED: 5684519de9aSGustavo F. Padovan case BT_CONFIG: 569715ec005SGustavo F. Padovan if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && 5704519de9aSGustavo F. Padovan conn->hcon->type == ACL_LINK) { 571c9b66675SGustavo F. Padovan __set_chan_timer(chan, sk->sk_sndtimeo); 5724519de9aSGustavo F. Padovan l2cap_send_disconn_req(conn, chan, reason); 5734519de9aSGustavo F. Padovan } else 5744519de9aSGustavo F. Padovan l2cap_chan_del(chan, reason); 5754519de9aSGustavo F. Padovan break; 5764519de9aSGustavo F. Padovan 5774519de9aSGustavo F. Padovan case BT_CONNECT2: 578715ec005SGustavo F. Padovan if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && 5794519de9aSGustavo F. Padovan conn->hcon->type == ACL_LINK) { 5804519de9aSGustavo F. Padovan struct l2cap_conn_rsp rsp; 5814519de9aSGustavo F. Padovan __u16 result; 5824519de9aSGustavo F. Padovan 5834519de9aSGustavo F. Padovan if (bt_sk(sk)->defer_setup) 5844519de9aSGustavo F. Padovan result = L2CAP_CR_SEC_BLOCK; 5854519de9aSGustavo F. Padovan else 5864519de9aSGustavo F. Padovan result = L2CAP_CR_BAD_PSM; 58789bc500eSGustavo F. Padovan l2cap_state_change(chan, BT_DISCONN); 5884519de9aSGustavo F. Padovan 5894519de9aSGustavo F. Padovan rsp.scid = cpu_to_le16(chan->dcid); 5904519de9aSGustavo F. Padovan rsp.dcid = cpu_to_le16(chan->scid); 5914519de9aSGustavo F. Padovan rsp.result = cpu_to_le16(result); 5924519de9aSGustavo F. Padovan rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); 5934519de9aSGustavo F. Padovan l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, 5944519de9aSGustavo F. Padovan sizeof(rsp), &rsp); 5954519de9aSGustavo F. Padovan } 5964519de9aSGustavo F. Padovan 5974519de9aSGustavo F. Padovan l2cap_chan_del(chan, reason); 5984519de9aSGustavo F. Padovan break; 5994519de9aSGustavo F. Padovan 6004519de9aSGustavo F. Padovan case BT_CONNECT: 6014519de9aSGustavo F. Padovan case BT_DISCONN: 6024519de9aSGustavo F. Padovan l2cap_chan_del(chan, reason); 6034519de9aSGustavo F. Padovan break; 6044519de9aSGustavo F. Padovan 6054519de9aSGustavo F. Padovan default: 6066be36555SAndrei Emeltchenko lock_sock(sk); 6074519de9aSGustavo F. Padovan sock_set_flag(sk, SOCK_ZAPPED); 6086be36555SAndrei Emeltchenko release_sock(sk); 6094519de9aSGustavo F. Padovan break; 6104519de9aSGustavo F. Padovan } 6114519de9aSGustavo F. Padovan } 6124519de9aSGustavo F. Padovan 6134343478fSGustavo F. Padovan static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) 6140a708f8fSGustavo F. Padovan { 615715ec005SGustavo F. Padovan if (chan->chan_type == L2CAP_CHAN_RAW) { 6164343478fSGustavo F. Padovan switch (chan->sec_level) { 6170a708f8fSGustavo F. Padovan case BT_SECURITY_HIGH: 6180a708f8fSGustavo F. Padovan return HCI_AT_DEDICATED_BONDING_MITM; 6190a708f8fSGustavo F. Padovan case BT_SECURITY_MEDIUM: 6200a708f8fSGustavo F. Padovan return HCI_AT_DEDICATED_BONDING; 6210a708f8fSGustavo F. Padovan default: 6220a708f8fSGustavo F. Padovan return HCI_AT_NO_BONDING; 6230a708f8fSGustavo F. Padovan } 624fe4128e0SGustavo F. Padovan } else if (chan->psm == cpu_to_le16(0x0001)) { 6254343478fSGustavo F. Padovan if (chan->sec_level == BT_SECURITY_LOW) 6264343478fSGustavo F. Padovan chan->sec_level = BT_SECURITY_SDP; 6270a708f8fSGustavo F. Padovan 6284343478fSGustavo F. Padovan if (chan->sec_level == BT_SECURITY_HIGH) 6290a708f8fSGustavo F. Padovan return HCI_AT_NO_BONDING_MITM; 6300a708f8fSGustavo F. Padovan else 6310a708f8fSGustavo F. Padovan return HCI_AT_NO_BONDING; 6320a708f8fSGustavo F. Padovan } else { 6334343478fSGustavo F. Padovan switch (chan->sec_level) { 6340a708f8fSGustavo F. Padovan case BT_SECURITY_HIGH: 6350a708f8fSGustavo F. Padovan return HCI_AT_GENERAL_BONDING_MITM; 6360a708f8fSGustavo F. Padovan case BT_SECURITY_MEDIUM: 6370a708f8fSGustavo F. Padovan return HCI_AT_GENERAL_BONDING; 6380a708f8fSGustavo F. Padovan default: 6390a708f8fSGustavo F. Padovan return HCI_AT_NO_BONDING; 6400a708f8fSGustavo F. Padovan } 6410a708f8fSGustavo F. Padovan } 6420a708f8fSGustavo F. Padovan } 6430a708f8fSGustavo F. Padovan 6440a708f8fSGustavo F. Padovan /* Service level security */ 645d45fc423SGustavo F. Padovan int l2cap_chan_check_security(struct l2cap_chan *chan) 6460a708f8fSGustavo F. Padovan { 6478c1d787bSGustavo F. Padovan struct l2cap_conn *conn = chan->conn; 6480a708f8fSGustavo F. Padovan __u8 auth_type; 6490a708f8fSGustavo F. Padovan 6504343478fSGustavo F. Padovan auth_type = l2cap_get_auth_type(chan); 6510a708f8fSGustavo F. Padovan 6524343478fSGustavo F. Padovan return hci_conn_security(conn->hcon, chan->sec_level, auth_type); 6530a708f8fSGustavo F. Padovan } 6540a708f8fSGustavo F. Padovan 655b5ad8b7fSJohannes Berg static u8 l2cap_get_ident(struct l2cap_conn *conn) 6560a708f8fSGustavo F. Padovan { 6570a708f8fSGustavo F. Padovan u8 id; 6580a708f8fSGustavo F. Padovan 6590a708f8fSGustavo F. Padovan /* Get next available identificator. 6600a708f8fSGustavo F. Padovan * 1 - 128 are used by kernel. 6610a708f8fSGustavo F. Padovan * 129 - 199 are reserved. 6620a708f8fSGustavo F. Padovan * 200 - 254 are used by utilities like l2ping, etc. 6630a708f8fSGustavo F. Padovan */ 6640a708f8fSGustavo F. Padovan 665333055f2SGustavo F. Padovan spin_lock(&conn->lock); 6660a708f8fSGustavo F. Padovan 6670a708f8fSGustavo F. Padovan if (++conn->tx_ident > 128) 6680a708f8fSGustavo F. Padovan conn->tx_ident = 1; 6690a708f8fSGustavo F. Padovan 6700a708f8fSGustavo F. Padovan id = conn->tx_ident; 6710a708f8fSGustavo F. Padovan 672333055f2SGustavo F. Padovan spin_unlock(&conn->lock); 6730a708f8fSGustavo F. Padovan 6740a708f8fSGustavo F. Padovan return id; 6750a708f8fSGustavo F. Padovan } 6760a708f8fSGustavo F. Padovan 6774519de9aSGustavo F. Padovan static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data) 6780a708f8fSGustavo F. Padovan { 6790a708f8fSGustavo F. Padovan struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data); 6800a708f8fSGustavo F. Padovan u8 flags; 6810a708f8fSGustavo F. Padovan 6820a708f8fSGustavo F. Padovan BT_DBG("code 0x%2.2x", code); 6830a708f8fSGustavo F. Padovan 6840a708f8fSGustavo F. Padovan if (!skb) 6850a708f8fSGustavo F. Padovan return; 6860a708f8fSGustavo F. Padovan 6870a708f8fSGustavo F. Padovan if (lmp_no_flush_capable(conn->hcon->hdev)) 6880a708f8fSGustavo F. Padovan flags = ACL_START_NO_FLUSH; 6890a708f8fSGustavo F. Padovan else 6900a708f8fSGustavo F. Padovan flags = ACL_START; 6910a708f8fSGustavo F. Padovan 69214b12d0bSJaikumar Ganesh bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON; 6935e59b791SLuiz Augusto von Dentz skb->priority = HCI_PRIO_MAX; 69414b12d0bSJaikumar Ganesh 69573d80debSLuiz Augusto von Dentz hci_send_acl(conn->hchan, skb, flags); 6960a708f8fSGustavo F. Padovan } 6970a708f8fSGustavo F. Padovan 69873d80debSLuiz Augusto von Dentz static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) 69973d80debSLuiz Augusto von Dentz { 70073d80debSLuiz Augusto von Dentz struct hci_conn *hcon = chan->conn->hcon; 70173d80debSLuiz Augusto von Dentz u16 flags; 70273d80debSLuiz Augusto von Dentz 70373d80debSLuiz Augusto von Dentz BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len, 70473d80debSLuiz Augusto von Dentz skb->priority); 70573d80debSLuiz Augusto von Dentz 70673d80debSLuiz Augusto von Dentz if (!test_bit(FLAG_FLUSHABLE, &chan->flags) && 70773d80debSLuiz Augusto von Dentz lmp_no_flush_capable(hcon->hdev)) 70873d80debSLuiz Augusto von Dentz flags = ACL_START_NO_FLUSH; 70973d80debSLuiz Augusto von Dentz else 71073d80debSLuiz Augusto von Dentz flags = ACL_START; 71173d80debSLuiz Augusto von Dentz 71273d80debSLuiz Augusto von Dentz bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags); 71373d80debSLuiz Augusto von Dentz hci_send_acl(chan->conn->hchan, skb, flags); 7140a708f8fSGustavo F. Padovan } 7150a708f8fSGustavo F. Padovan 716b5c6aaedSMat Martineau static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control) 717b5c6aaedSMat Martineau { 718b5c6aaedSMat Martineau control->reqseq = (enh & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT; 719b5c6aaedSMat Martineau control->final = (enh & L2CAP_CTRL_FINAL) >> L2CAP_CTRL_FINAL_SHIFT; 720b5c6aaedSMat Martineau 721b5c6aaedSMat Martineau if (enh & L2CAP_CTRL_FRAME_TYPE) { 722b5c6aaedSMat Martineau /* S-Frame */ 723b5c6aaedSMat Martineau control->sframe = 1; 724b5c6aaedSMat Martineau control->poll = (enh & L2CAP_CTRL_POLL) >> L2CAP_CTRL_POLL_SHIFT; 725b5c6aaedSMat Martineau control->super = (enh & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT; 726b5c6aaedSMat Martineau 727b5c6aaedSMat Martineau control->sar = 0; 728b5c6aaedSMat Martineau control->txseq = 0; 729b5c6aaedSMat Martineau } else { 730b5c6aaedSMat Martineau /* I-Frame */ 731b5c6aaedSMat Martineau control->sframe = 0; 732b5c6aaedSMat Martineau control->sar = (enh & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT; 733b5c6aaedSMat Martineau control->txseq = (enh & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT; 734b5c6aaedSMat Martineau 735b5c6aaedSMat Martineau control->poll = 0; 736b5c6aaedSMat Martineau control->super = 0; 737b5c6aaedSMat Martineau } 738b5c6aaedSMat Martineau } 739b5c6aaedSMat Martineau 740b5c6aaedSMat Martineau static void __unpack_extended_control(u32 ext, struct l2cap_ctrl *control) 741b5c6aaedSMat Martineau { 742b5c6aaedSMat Martineau control->reqseq = (ext & L2CAP_EXT_CTRL_REQSEQ) >> L2CAP_EXT_CTRL_REQSEQ_SHIFT; 743b5c6aaedSMat Martineau control->final = (ext & L2CAP_EXT_CTRL_FINAL) >> L2CAP_EXT_CTRL_FINAL_SHIFT; 744b5c6aaedSMat Martineau 745b5c6aaedSMat Martineau if (ext & L2CAP_EXT_CTRL_FRAME_TYPE) { 746b5c6aaedSMat Martineau /* S-Frame */ 747b5c6aaedSMat Martineau control->sframe = 1; 748b5c6aaedSMat Martineau control->poll = (ext & L2CAP_EXT_CTRL_POLL) >> L2CAP_EXT_CTRL_POLL_SHIFT; 749b5c6aaedSMat Martineau control->super = (ext & L2CAP_EXT_CTRL_SUPERVISE) >> L2CAP_EXT_CTRL_SUPER_SHIFT; 750b5c6aaedSMat Martineau 751b5c6aaedSMat Martineau control->sar = 0; 752b5c6aaedSMat Martineau control->txseq = 0; 753b5c6aaedSMat Martineau } else { 754b5c6aaedSMat Martineau /* I-Frame */ 755b5c6aaedSMat Martineau control->sframe = 0; 756b5c6aaedSMat Martineau control->sar = (ext & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT; 757b5c6aaedSMat Martineau control->txseq = (ext & L2CAP_EXT_CTRL_TXSEQ) >> L2CAP_EXT_CTRL_TXSEQ_SHIFT; 758b5c6aaedSMat Martineau 759b5c6aaedSMat Martineau control->poll = 0; 760b5c6aaedSMat Martineau control->super = 0; 761b5c6aaedSMat Martineau } 762b5c6aaedSMat Martineau } 763b5c6aaedSMat Martineau 764b5c6aaedSMat Martineau static inline void __unpack_control(struct l2cap_chan *chan, 765b5c6aaedSMat Martineau struct sk_buff *skb) 766b5c6aaedSMat Martineau { 767b5c6aaedSMat Martineau if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { 768b5c6aaedSMat Martineau __unpack_extended_control(get_unaligned_le32(skb->data), 769b5c6aaedSMat Martineau &bt_cb(skb)->control); 770b5c6aaedSMat Martineau } else { 771b5c6aaedSMat Martineau __unpack_enhanced_control(get_unaligned_le16(skb->data), 772b5c6aaedSMat Martineau &bt_cb(skb)->control); 773b5c6aaedSMat Martineau } 774b5c6aaedSMat Martineau } 775b5c6aaedSMat Martineau 776b5c6aaedSMat Martineau static u32 __pack_extended_control(struct l2cap_ctrl *control) 777b5c6aaedSMat Martineau { 778b5c6aaedSMat Martineau u32 packed; 779b5c6aaedSMat Martineau 780b5c6aaedSMat Martineau packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT; 781b5c6aaedSMat Martineau packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT; 782b5c6aaedSMat Martineau 783b5c6aaedSMat Martineau if (control->sframe) { 784b5c6aaedSMat Martineau packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT; 785b5c6aaedSMat Martineau packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT; 786b5c6aaedSMat Martineau packed |= L2CAP_EXT_CTRL_FRAME_TYPE; 787b5c6aaedSMat Martineau } else { 788b5c6aaedSMat Martineau packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT; 789b5c6aaedSMat Martineau packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT; 790b5c6aaedSMat Martineau } 791b5c6aaedSMat Martineau 792b5c6aaedSMat Martineau return packed; 793b5c6aaedSMat Martineau } 794b5c6aaedSMat Martineau 795b5c6aaedSMat Martineau static u16 __pack_enhanced_control(struct l2cap_ctrl *control) 796b5c6aaedSMat Martineau { 797b5c6aaedSMat Martineau u16 packed; 798b5c6aaedSMat Martineau 799b5c6aaedSMat Martineau packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT; 800b5c6aaedSMat Martineau packed |= control->final << L2CAP_CTRL_FINAL_SHIFT; 801b5c6aaedSMat Martineau 802b5c6aaedSMat Martineau if (control->sframe) { 803b5c6aaedSMat Martineau packed |= control->poll << L2CAP_CTRL_POLL_SHIFT; 804b5c6aaedSMat Martineau packed |= control->super << L2CAP_CTRL_SUPER_SHIFT; 805b5c6aaedSMat Martineau packed |= L2CAP_CTRL_FRAME_TYPE; 806b5c6aaedSMat Martineau } else { 807b5c6aaedSMat Martineau packed |= control->sar << L2CAP_CTRL_SAR_SHIFT; 808b5c6aaedSMat Martineau packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT; 809b5c6aaedSMat Martineau } 810b5c6aaedSMat Martineau 811b5c6aaedSMat Martineau return packed; 812b5c6aaedSMat Martineau } 813b5c6aaedSMat Martineau 814b5c6aaedSMat Martineau static inline void __pack_control(struct l2cap_chan *chan, 815b5c6aaedSMat Martineau struct l2cap_ctrl *control, 816b5c6aaedSMat Martineau struct sk_buff *skb) 817b5c6aaedSMat Martineau { 818b5c6aaedSMat Martineau if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { 819b5c6aaedSMat Martineau put_unaligned_le32(__pack_extended_control(control), 820b5c6aaedSMat Martineau skb->data + L2CAP_HDR_SIZE); 821b5c6aaedSMat Martineau } else { 822b5c6aaedSMat Martineau put_unaligned_le16(__pack_enhanced_control(control), 823b5c6aaedSMat Martineau skb->data + L2CAP_HDR_SIZE); 824b5c6aaedSMat Martineau } 825b5c6aaedSMat Martineau } 826b5c6aaedSMat Martineau 82788843ab0SAndrei Emeltchenko static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) 8280a708f8fSGustavo F. Padovan { 8290a708f8fSGustavo F. Padovan struct sk_buff *skb; 8300a708f8fSGustavo F. Padovan struct l2cap_hdr *lh; 8318c1d787bSGustavo F. Padovan struct l2cap_conn *conn = chan->conn; 832e4ca6d98SAndrei Emeltchenko int count, hlen; 8330a708f8fSGustavo F. Padovan 83489bc500eSGustavo F. Padovan if (chan->state != BT_CONNECTED) 8350a708f8fSGustavo F. Padovan return; 8360a708f8fSGustavo F. Padovan 837e4ca6d98SAndrei Emeltchenko if (test_bit(FLAG_EXT_CTRL, &chan->flags)) 838e4ca6d98SAndrei Emeltchenko hlen = L2CAP_EXT_HDR_SIZE; 839e4ca6d98SAndrei Emeltchenko else 840e4ca6d98SAndrei Emeltchenko hlen = L2CAP_ENH_HDR_SIZE; 8410a708f8fSGustavo F. Padovan 8420a708f8fSGustavo F. Padovan if (chan->fcs == L2CAP_FCS_CRC16) 84303a51213SAndrei Emeltchenko hlen += L2CAP_FCS_SIZE; 8440a708f8fSGustavo F. Padovan 84588843ab0SAndrei Emeltchenko BT_DBG("chan %p, control 0x%8.8x", chan, control); 8460a708f8fSGustavo F. Padovan 8470a708f8fSGustavo F. Padovan count = min_t(unsigned int, conn->mtu, hlen); 848793c2f1cSAndrei Emeltchenko 849793c2f1cSAndrei Emeltchenko control |= __set_sframe(chan); 8500a708f8fSGustavo F. Padovan 851e2ab4353SGustavo F. Padovan if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) 85203f6715dSAndrei Emeltchenko control |= __set_ctrl_final(chan); 8530a708f8fSGustavo F. Padovan 854e2ab4353SGustavo F. Padovan if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state)) 855e3781735SAndrei Emeltchenko control |= __set_ctrl_poll(chan); 8560a708f8fSGustavo F. Padovan 8570a708f8fSGustavo F. Padovan skb = bt_skb_alloc(count, GFP_ATOMIC); 8580a708f8fSGustavo F. Padovan if (!skb) 8590a708f8fSGustavo F. Padovan return; 8600a708f8fSGustavo F. Padovan 8610a708f8fSGustavo F. Padovan lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); 8620a708f8fSGustavo F. Padovan lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE); 863fe4128e0SGustavo F. Padovan lh->cid = cpu_to_le16(chan->dcid); 86488843ab0SAndrei Emeltchenko 86588843ab0SAndrei Emeltchenko __put_control(chan, control, skb_put(skb, __ctrl_size(chan))); 8660a708f8fSGustavo F. Padovan 86747d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_CRC16) { 86803a51213SAndrei Emeltchenko u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE); 86903a51213SAndrei Emeltchenko put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE)); 8700a708f8fSGustavo F. Padovan } 8710a708f8fSGustavo F. Padovan 87273d80debSLuiz Augusto von Dentz skb->priority = HCI_PRIO_MAX; 87373d80debSLuiz Augusto von Dentz l2cap_do_send(chan, skb); 8740a708f8fSGustavo F. Padovan } 8750a708f8fSGustavo F. Padovan 87688843ab0SAndrei Emeltchenko static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control) 8770a708f8fSGustavo F. Padovan { 878e2ab4353SGustavo F. Padovan if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { 879ab784b73SAndrei Emeltchenko control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); 880e2ab4353SGustavo F. Padovan set_bit(CONN_RNR_SENT, &chan->conn_state); 8810a708f8fSGustavo F. Padovan } else 882ab784b73SAndrei Emeltchenko control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); 8830a708f8fSGustavo F. Padovan 8840b209faeSAndrei Emeltchenko control |= __set_reqseq(chan, chan->buffer_seq); 8850a708f8fSGustavo F. Padovan 886525cd185SGustavo F. Padovan l2cap_send_sframe(chan, control); 8870a708f8fSGustavo F. Padovan } 8880a708f8fSGustavo F. Padovan 889b4450035SGustavo F. Padovan static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) 8900a708f8fSGustavo F. Padovan { 891c1360a1cSGustavo F. Padovan return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); 8920a708f8fSGustavo F. Padovan } 8930a708f8fSGustavo F. Padovan 8949b27f350SAndrei Emeltchenko static void l2cap_send_conn_req(struct l2cap_chan *chan) 8959b27f350SAndrei Emeltchenko { 8969b27f350SAndrei Emeltchenko struct l2cap_conn *conn = chan->conn; 8979b27f350SAndrei Emeltchenko struct l2cap_conn_req req; 8989b27f350SAndrei Emeltchenko 8999b27f350SAndrei Emeltchenko req.scid = cpu_to_le16(chan->scid); 9009b27f350SAndrei Emeltchenko req.psm = chan->psm; 9019b27f350SAndrei Emeltchenko 9029b27f350SAndrei Emeltchenko chan->ident = l2cap_get_ident(conn); 9039b27f350SAndrei Emeltchenko 9049b27f350SAndrei Emeltchenko set_bit(CONF_CONNECT_PEND, &chan->conf_state); 9059b27f350SAndrei Emeltchenko 9069b27f350SAndrei Emeltchenko l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); 9079b27f350SAndrei Emeltchenko } 9089b27f350SAndrei Emeltchenko 9099f0caeb1SVinicius Costa Gomes static void l2cap_chan_ready(struct l2cap_chan *chan) 9109f0caeb1SVinicius Costa Gomes { 9119f0caeb1SVinicius Costa Gomes struct sock *sk = chan->sk; 9129f0caeb1SVinicius Costa Gomes struct sock *parent; 9139f0caeb1SVinicius Costa Gomes 9149f0caeb1SVinicius Costa Gomes lock_sock(sk); 9159f0caeb1SVinicius Costa Gomes 9169f0caeb1SVinicius Costa Gomes parent = bt_sk(sk)->parent; 9179f0caeb1SVinicius Costa Gomes 9189f0caeb1SVinicius Costa Gomes BT_DBG("sk %p, parent %p", sk, parent); 9199f0caeb1SVinicius Costa Gomes 9209f0caeb1SVinicius Costa Gomes chan->conf_state = 0; 9219f0caeb1SVinicius Costa Gomes __clear_chan_timer(chan); 9229f0caeb1SVinicius Costa Gomes 9239f0caeb1SVinicius Costa Gomes __l2cap_state_change(chan, BT_CONNECTED); 9249f0caeb1SVinicius Costa Gomes sk->sk_state_change(sk); 9259f0caeb1SVinicius Costa Gomes 9269f0caeb1SVinicius Costa Gomes if (parent) 9279f0caeb1SVinicius Costa Gomes parent->sk_data_ready(parent, 0); 9289f0caeb1SVinicius Costa Gomes 9299f0caeb1SVinicius Costa Gomes release_sock(sk); 9309f0caeb1SVinicius Costa Gomes } 9319f0caeb1SVinicius Costa Gomes 932fc7f8a7eSGustavo F. Padovan static void l2cap_do_start(struct l2cap_chan *chan) 9330a708f8fSGustavo F. Padovan { 9348c1d787bSGustavo F. Padovan struct l2cap_conn *conn = chan->conn; 9350a708f8fSGustavo F. Padovan 9369f0caeb1SVinicius Costa Gomes if (conn->hcon->type == LE_LINK) { 9379f0caeb1SVinicius Costa Gomes l2cap_chan_ready(chan); 9389f0caeb1SVinicius Costa Gomes return; 9399f0caeb1SVinicius Costa Gomes } 9409f0caeb1SVinicius Costa Gomes 9410a708f8fSGustavo F. Padovan if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { 9420a708f8fSGustavo F. Padovan if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) 9430a708f8fSGustavo F. Padovan return; 9440a708f8fSGustavo F. Padovan 945d45fc423SGustavo F. Padovan if (l2cap_chan_check_security(chan) && 9469b27f350SAndrei Emeltchenko __l2cap_no_conn_pending(chan)) 9479b27f350SAndrei Emeltchenko l2cap_send_conn_req(chan); 9480a708f8fSGustavo F. Padovan } else { 9490a708f8fSGustavo F. Padovan struct l2cap_info_req req; 9500a708f8fSGustavo F. Padovan req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); 9510a708f8fSGustavo F. Padovan 9520a708f8fSGustavo F. Padovan conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; 9530a708f8fSGustavo F. Padovan conn->info_ident = l2cap_get_ident(conn); 9540a708f8fSGustavo F. Padovan 955ba13ccd9SMarcel Holtmann schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT); 9560a708f8fSGustavo F. Padovan 9570a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, conn->info_ident, 9580a708f8fSGustavo F. Padovan L2CAP_INFO_REQ, sizeof(req), &req); 9590a708f8fSGustavo F. Padovan } 9600a708f8fSGustavo F. Padovan } 9610a708f8fSGustavo F. Padovan 9620a708f8fSGustavo F. Padovan static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) 9630a708f8fSGustavo F. Padovan { 9640a708f8fSGustavo F. Padovan u32 local_feat_mask = l2cap_feat_mask; 9650a708f8fSGustavo F. Padovan if (!disable_ertm) 9660a708f8fSGustavo F. Padovan local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING; 9670a708f8fSGustavo F. Padovan 9680a708f8fSGustavo F. Padovan switch (mode) { 9690a708f8fSGustavo F. Padovan case L2CAP_MODE_ERTM: 9700a708f8fSGustavo F. Padovan return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask; 9710a708f8fSGustavo F. Padovan case L2CAP_MODE_STREAMING: 9720a708f8fSGustavo F. Padovan return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask; 9730a708f8fSGustavo F. Padovan default: 9740a708f8fSGustavo F. Padovan return 0x00; 9750a708f8fSGustavo F. Padovan } 9760a708f8fSGustavo F. Padovan } 9770a708f8fSGustavo F. Padovan 9784519de9aSGustavo F. Padovan static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err) 9790a708f8fSGustavo F. Padovan { 9806be36555SAndrei Emeltchenko struct sock *sk = chan->sk; 9810a708f8fSGustavo F. Padovan struct l2cap_disconn_req req; 9820a708f8fSGustavo F. Padovan 9830a708f8fSGustavo F. Padovan if (!conn) 9840a708f8fSGustavo F. Padovan return; 9850a708f8fSGustavo F. Padovan 9860c1bc5c6SGustavo F. Padovan if (chan->mode == L2CAP_MODE_ERTM) { 9871a09bcb9SGustavo F. Padovan __clear_retrans_timer(chan); 9881a09bcb9SGustavo F. Padovan __clear_monitor_timer(chan); 9891a09bcb9SGustavo F. Padovan __clear_ack_timer(chan); 9900a708f8fSGustavo F. Padovan } 9910a708f8fSGustavo F. Padovan 992fe4128e0SGustavo F. Padovan req.dcid = cpu_to_le16(chan->dcid); 993fe4128e0SGustavo F. Padovan req.scid = cpu_to_le16(chan->scid); 9940a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, l2cap_get_ident(conn), 9950a708f8fSGustavo F. Padovan L2CAP_DISCONN_REQ, sizeof(req), &req); 9960a708f8fSGustavo F. Padovan 9976be36555SAndrei Emeltchenko lock_sock(sk); 9980e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_DISCONN); 9992e0052e4SAndrei Emeltchenko __l2cap_chan_set_err(chan, err); 10006be36555SAndrei Emeltchenko release_sock(sk); 10010a708f8fSGustavo F. Padovan } 10020a708f8fSGustavo F. Padovan 10030a708f8fSGustavo F. Padovan /* ---- L2CAP connections ---- */ 10040a708f8fSGustavo F. Padovan static void l2cap_conn_start(struct l2cap_conn *conn) 10050a708f8fSGustavo F. Padovan { 10063df91ea2SAndrei Emeltchenko struct l2cap_chan *chan, *tmp; 10070a708f8fSGustavo F. Padovan 10080a708f8fSGustavo F. Padovan BT_DBG("conn %p", conn); 10090a708f8fSGustavo F. Padovan 10103df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 10110a708f8fSGustavo F. Padovan 10123df91ea2SAndrei Emeltchenko list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { 101348454079SGustavo F. Padovan struct sock *sk = chan->sk; 1014baa7e1faSGustavo F. Padovan 10156be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 10160a708f8fSGustavo F. Padovan 1017715ec005SGustavo F. Padovan if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { 10186be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 10190a708f8fSGustavo F. Padovan continue; 10200a708f8fSGustavo F. Padovan } 10210a708f8fSGustavo F. Padovan 102289bc500eSGustavo F. Padovan if (chan->state == BT_CONNECT) { 1023d45fc423SGustavo F. Padovan if (!l2cap_chan_check_security(chan) || 1024b4450035SGustavo F. Padovan !__l2cap_no_conn_pending(chan)) { 10256be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 10260a708f8fSGustavo F. Padovan continue; 10270a708f8fSGustavo F. Padovan } 10280a708f8fSGustavo F. Padovan 1029c1360a1cSGustavo F. Padovan if (!l2cap_mode_supported(chan->mode, conn->feat_mask) 1030c1360a1cSGustavo F. Padovan && test_bit(CONF_STATE2_DEVICE, 1031c1360a1cSGustavo F. Padovan &chan->conf_state)) { 10320f852724SGustavo F. Padovan l2cap_chan_close(chan, ECONNRESET); 10336be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 10340a708f8fSGustavo F. Padovan continue; 10350a708f8fSGustavo F. Padovan } 10360a708f8fSGustavo F. Padovan 10379b27f350SAndrei Emeltchenko l2cap_send_conn_req(chan); 10380a708f8fSGustavo F. Padovan 103989bc500eSGustavo F. Padovan } else if (chan->state == BT_CONNECT2) { 10400a708f8fSGustavo F. Padovan struct l2cap_conn_rsp rsp; 10410a708f8fSGustavo F. Padovan char buf[128]; 1042fe4128e0SGustavo F. Padovan rsp.scid = cpu_to_le16(chan->dcid); 1043fe4128e0SGustavo F. Padovan rsp.dcid = cpu_to_le16(chan->scid); 10440a708f8fSGustavo F. Padovan 1045d45fc423SGustavo F. Padovan if (l2cap_chan_check_security(chan)) { 10466be36555SAndrei Emeltchenko lock_sock(sk); 10470a708f8fSGustavo F. Padovan if (bt_sk(sk)->defer_setup) { 10480a708f8fSGustavo F. Padovan struct sock *parent = bt_sk(sk)->parent; 10490a708f8fSGustavo F. Padovan rsp.result = cpu_to_le16(L2CAP_CR_PEND); 10500a708f8fSGustavo F. Padovan rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); 105105e9a2f6SIlia Kolomisnky if (parent) 10520a708f8fSGustavo F. Padovan parent->sk_data_ready(parent, 0); 10530a708f8fSGustavo F. Padovan 10540a708f8fSGustavo F. Padovan } else { 10550e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_CONFIG); 10560a708f8fSGustavo F. Padovan rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); 10570a708f8fSGustavo F. Padovan rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); 10580a708f8fSGustavo F. Padovan } 10596be36555SAndrei Emeltchenko release_sock(sk); 10600a708f8fSGustavo F. Padovan } else { 10610a708f8fSGustavo F. Padovan rsp.result = cpu_to_le16(L2CAP_CR_PEND); 10620a708f8fSGustavo F. Padovan rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); 10630a708f8fSGustavo F. Padovan } 10640a708f8fSGustavo F. Padovan 1065fc7f8a7eSGustavo F. Padovan l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, 1066fc7f8a7eSGustavo F. Padovan sizeof(rsp), &rsp); 10670a708f8fSGustavo F. Padovan 1068c1360a1cSGustavo F. Padovan if (test_bit(CONF_REQ_SENT, &chan->conf_state) || 10690a708f8fSGustavo F. Padovan rsp.result != L2CAP_CR_SUCCESS) { 10706be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 10710a708f8fSGustavo F. Padovan continue; 10720a708f8fSGustavo F. Padovan } 10730a708f8fSGustavo F. Padovan 1074c1360a1cSGustavo F. Padovan set_bit(CONF_REQ_SENT, &chan->conf_state); 10750a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, 107673ffa904SGustavo F. Padovan l2cap_build_conf_req(chan, buf), buf); 107773ffa904SGustavo F. Padovan chan->num_conf_req++; 10780a708f8fSGustavo F. Padovan } 10790a708f8fSGustavo F. Padovan 10806be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 10810a708f8fSGustavo F. Padovan } 10820a708f8fSGustavo F. Padovan 10833df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 10840a708f8fSGustavo F. Padovan } 10850a708f8fSGustavo F. Padovan 1086c2287681SIdo Yariv /* Find socket with cid and source/destination bdaddr. 1087b62f328bSVille Tervo * Returns closest match, locked. 1088b62f328bSVille Tervo */ 1089d9b88702SAndrei Emeltchenko static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, 1090c2287681SIdo Yariv bdaddr_t *src, 1091c2287681SIdo Yariv bdaddr_t *dst) 1092b62f328bSVille Tervo { 109323691d75SGustavo F. Padovan struct l2cap_chan *c, *c1 = NULL; 1094b62f328bSVille Tervo 109523691d75SGustavo F. Padovan read_lock(&chan_list_lock); 1096b62f328bSVille Tervo 109723691d75SGustavo F. Padovan list_for_each_entry(c, &chan_list, global_l) { 109823691d75SGustavo F. Padovan struct sock *sk = c->sk; 1099fe4128e0SGustavo F. Padovan 110089bc500eSGustavo F. Padovan if (state && c->state != state) 1101b62f328bSVille Tervo continue; 1102b62f328bSVille Tervo 110323691d75SGustavo F. Padovan if (c->scid == cid) { 1104c2287681SIdo Yariv int src_match, dst_match; 1105c2287681SIdo Yariv int src_any, dst_any; 1106c2287681SIdo Yariv 1107b62f328bSVille Tervo /* Exact match. */ 1108c2287681SIdo Yariv src_match = !bacmp(&bt_sk(sk)->src, src); 1109c2287681SIdo Yariv dst_match = !bacmp(&bt_sk(sk)->dst, dst); 1110c2287681SIdo Yariv if (src_match && dst_match) { 111123691d75SGustavo F. Padovan read_unlock(&chan_list_lock); 111223691d75SGustavo F. Padovan return c; 111323691d75SGustavo F. Padovan } 1114b62f328bSVille Tervo 1115b62f328bSVille Tervo /* Closest match */ 1116c2287681SIdo Yariv src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY); 1117c2287681SIdo Yariv dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY); 1118c2287681SIdo Yariv if ((src_match && dst_any) || (src_any && dst_match) || 1119c2287681SIdo Yariv (src_any && dst_any)) 112023691d75SGustavo F. Padovan c1 = c; 1121b62f328bSVille Tervo } 1122b62f328bSVille Tervo } 1123280f294fSGustavo F. Padovan 112423691d75SGustavo F. Padovan read_unlock(&chan_list_lock); 1125b62f328bSVille Tervo 112623691d75SGustavo F. Padovan return c1; 1127b62f328bSVille Tervo } 1128b62f328bSVille Tervo 1129b62f328bSVille Tervo static void l2cap_le_conn_ready(struct l2cap_conn *conn) 1130b62f328bSVille Tervo { 1131c916fbe4SGustavo F. Padovan struct sock *parent, *sk; 113223691d75SGustavo F. Padovan struct l2cap_chan *chan, *pchan; 1133b62f328bSVille Tervo 1134b62f328bSVille Tervo BT_DBG(""); 1135b62f328bSVille Tervo 1136b62f328bSVille Tervo /* Check if we have socket listening on cid */ 113723691d75SGustavo F. Padovan pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, 1138c2287681SIdo Yariv conn->src, conn->dst); 113923691d75SGustavo F. Padovan if (!pchan) 1140b62f328bSVille Tervo return; 1141b62f328bSVille Tervo 114223691d75SGustavo F. Padovan parent = pchan->sk; 114323691d75SGustavo F. Padovan 1144aa2ac881SGustavo F. Padovan lock_sock(parent); 114562f3a2cfSGustavo F. Padovan 1146b62f328bSVille Tervo /* Check for backlog size */ 1147b62f328bSVille Tervo if (sk_acceptq_is_full(parent)) { 1148b62f328bSVille Tervo BT_DBG("backlog full %d", parent->sk_ack_backlog); 1149b62f328bSVille Tervo goto clean; 1150b62f328bSVille Tervo } 1151b62f328bSVille Tervo 115280808e43SGustavo F. Padovan chan = pchan->ops->new_connection(pchan->data); 115380808e43SGustavo F. Padovan if (!chan) 1154b62f328bSVille Tervo goto clean; 1155b62f328bSVille Tervo 115680808e43SGustavo F. Padovan sk = chan->sk; 11575d41ce1dSGustavo F. Padovan 1158b62f328bSVille Tervo hci_conn_hold(conn->hcon); 1159b62f328bSVille Tervo 1160b62f328bSVille Tervo bacpy(&bt_sk(sk)->src, conn->src); 1161b62f328bSVille Tervo bacpy(&bt_sk(sk)->dst, conn->dst); 1162b62f328bSVille Tervo 1163d1010240SGustavo F. Padovan bt_accept_enqueue(parent, sk); 1164d1010240SGustavo F. Padovan 11653d57dc68SGustavo F. Padovan l2cap_chan_add(conn, chan); 116648454079SGustavo F. Padovan 1167c9b66675SGustavo F. Padovan __set_chan_timer(chan, sk->sk_sndtimeo); 1168b62f328bSVille Tervo 11690e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_CONNECTED); 1170b62f328bSVille Tervo parent->sk_data_ready(parent, 0); 1171b62f328bSVille Tervo 1172b62f328bSVille Tervo clean: 1173aa2ac881SGustavo F. Padovan release_sock(parent); 1174b62f328bSVille Tervo } 1175b62f328bSVille Tervo 11760a708f8fSGustavo F. Padovan static void l2cap_conn_ready(struct l2cap_conn *conn) 11770a708f8fSGustavo F. Padovan { 117848454079SGustavo F. Padovan struct l2cap_chan *chan; 11790a708f8fSGustavo F. Padovan 11800a708f8fSGustavo F. Padovan BT_DBG("conn %p", conn); 11810a708f8fSGustavo F. Padovan 1182b62f328bSVille Tervo if (!conn->hcon->out && conn->hcon->type == LE_LINK) 1183b62f328bSVille Tervo l2cap_le_conn_ready(conn); 1184b62f328bSVille Tervo 1185160dc6acSVinicius Costa Gomes if (conn->hcon->out && conn->hcon->type == LE_LINK) 1186160dc6acSVinicius Costa Gomes smp_conn_security(conn, conn->hcon->pending_sec_level); 1187160dc6acSVinicius Costa Gomes 11883df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 11890a708f8fSGustavo F. Padovan 11903df91ea2SAndrei Emeltchenko list_for_each_entry(chan, &conn->chan_l, list) { 1191baa7e1faSGustavo F. Padovan 11926be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 11930a708f8fSGustavo F. Padovan 119463128451SVinicius Costa Gomes if (conn->hcon->type == LE_LINK) { 1195b501d6a1SAnderson Briglia if (smp_conn_security(conn, chan->sec_level)) 1196cf4cd009SAndrei Emeltchenko l2cap_chan_ready(chan); 1197acd7d370SVille Tervo 119863128451SVinicius Costa Gomes } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { 11996be36555SAndrei Emeltchenko struct sock *sk = chan->sk; 1200c9b66675SGustavo F. Padovan __clear_chan_timer(chan); 12016be36555SAndrei Emeltchenko lock_sock(sk); 12020e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_CONNECTED); 12030a708f8fSGustavo F. Padovan sk->sk_state_change(sk); 12046be36555SAndrei Emeltchenko release_sock(sk); 1205b501d6a1SAnderson Briglia 120689bc500eSGustavo F. Padovan } else if (chan->state == BT_CONNECT) 1207fc7f8a7eSGustavo F. Padovan l2cap_do_start(chan); 12080a708f8fSGustavo F. Padovan 12096be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 12100a708f8fSGustavo F. Padovan } 12110a708f8fSGustavo F. Padovan 12123df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 12130a708f8fSGustavo F. Padovan } 12140a708f8fSGustavo F. Padovan 12150a708f8fSGustavo F. Padovan /* Notify sockets that we cannot guaranty reliability anymore */ 12160a708f8fSGustavo F. Padovan static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) 12170a708f8fSGustavo F. Padovan { 121848454079SGustavo F. Padovan struct l2cap_chan *chan; 12190a708f8fSGustavo F. Padovan 12200a708f8fSGustavo F. Padovan BT_DBG("conn %p", conn); 12210a708f8fSGustavo F. Padovan 12223df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 12230a708f8fSGustavo F. Padovan 12243df91ea2SAndrei Emeltchenko list_for_each_entry(chan, &conn->chan_l, list) { 1225ecf61bdbSAndrei Emeltchenko if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags)) 12262e0052e4SAndrei Emeltchenko __l2cap_chan_set_err(chan, err); 12270a708f8fSGustavo F. Padovan } 12280a708f8fSGustavo F. Padovan 12293df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 12300a708f8fSGustavo F. Padovan } 12310a708f8fSGustavo F. Padovan 1232f878fcadSGustavo F. Padovan static void l2cap_info_timeout(struct work_struct *work) 12330a708f8fSGustavo F. Padovan { 1234f878fcadSGustavo F. Padovan struct l2cap_conn *conn = container_of(work, struct l2cap_conn, 1235030013d8SGustavo F. Padovan info_timer.work); 12360a708f8fSGustavo F. Padovan 12370a708f8fSGustavo F. Padovan conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; 12380a708f8fSGustavo F. Padovan conn->info_ident = 0; 12390a708f8fSGustavo F. Padovan 12400a708f8fSGustavo F. Padovan l2cap_conn_start(conn); 12410a708f8fSGustavo F. Padovan } 12420a708f8fSGustavo F. Padovan 12435d3de7dfSVinicius Costa Gomes static void l2cap_conn_del(struct hci_conn *hcon, int err) 12445d3de7dfSVinicius Costa Gomes { 12455d3de7dfSVinicius Costa Gomes struct l2cap_conn *conn = hcon->l2cap_data; 12465d3de7dfSVinicius Costa Gomes struct l2cap_chan *chan, *l; 12475d3de7dfSVinicius Costa Gomes 12485d3de7dfSVinicius Costa Gomes if (!conn) 12495d3de7dfSVinicius Costa Gomes return; 12505d3de7dfSVinicius Costa Gomes 12515d3de7dfSVinicius Costa Gomes BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); 12525d3de7dfSVinicius Costa Gomes 12535d3de7dfSVinicius Costa Gomes kfree_skb(conn->rx_skb); 12545d3de7dfSVinicius Costa Gomes 12553df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 12563df91ea2SAndrei Emeltchenko 12575d3de7dfSVinicius Costa Gomes /* Kill channels */ 12585d3de7dfSVinicius Costa Gomes list_for_each_entry_safe(chan, l, &conn->chan_l, list) { 1259*61d6ef3eSMat Martineau l2cap_chan_hold(chan); 12606be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 12616be36555SAndrei Emeltchenko 12625d3de7dfSVinicius Costa Gomes l2cap_chan_del(chan, err); 12636be36555SAndrei Emeltchenko 12646be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 12656be36555SAndrei Emeltchenko 12665d3de7dfSVinicius Costa Gomes chan->ops->close(chan->data); 1267*61d6ef3eSMat Martineau l2cap_chan_put(chan); 12685d3de7dfSVinicius Costa Gomes } 12695d3de7dfSVinicius Costa Gomes 12703df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 12713df91ea2SAndrei Emeltchenko 127273d80debSLuiz Augusto von Dentz hci_chan_del(conn->hchan); 127373d80debSLuiz Augusto von Dentz 12745d3de7dfSVinicius Costa Gomes if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) 1275127074bfSUlisses Furquim cancel_delayed_work_sync(&conn->info_timer); 12765d3de7dfSVinicius Costa Gomes 127751a8efd7SJohan Hedberg if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) { 1278127074bfSUlisses Furquim cancel_delayed_work_sync(&conn->security_timer); 12798aab4757SVinicius Costa Gomes smp_chan_destroy(conn); 1280d26a2345SVinicius Costa Gomes } 12815d3de7dfSVinicius Costa Gomes 12825d3de7dfSVinicius Costa Gomes hcon->l2cap_data = NULL; 12835d3de7dfSVinicius Costa Gomes kfree(conn); 12845d3de7dfSVinicius Costa Gomes } 12855d3de7dfSVinicius Costa Gomes 12866c9d42a1SGustavo F. Padovan static void security_timeout(struct work_struct *work) 12875d3de7dfSVinicius Costa Gomes { 12886c9d42a1SGustavo F. Padovan struct l2cap_conn *conn = container_of(work, struct l2cap_conn, 12896c9d42a1SGustavo F. Padovan security_timer.work); 12905d3de7dfSVinicius Costa Gomes 12915d3de7dfSVinicius Costa Gomes l2cap_conn_del(conn->hcon, ETIMEDOUT); 12925d3de7dfSVinicius Costa Gomes } 12935d3de7dfSVinicius Costa Gomes 12940a708f8fSGustavo F. Padovan static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) 12950a708f8fSGustavo F. Padovan { 12960a708f8fSGustavo F. Padovan struct l2cap_conn *conn = hcon->l2cap_data; 129773d80debSLuiz Augusto von Dentz struct hci_chan *hchan; 12980a708f8fSGustavo F. Padovan 12990a708f8fSGustavo F. Padovan if (conn || status) 13000a708f8fSGustavo F. Padovan return conn; 13010a708f8fSGustavo F. Padovan 130273d80debSLuiz Augusto von Dentz hchan = hci_chan_create(hcon); 130373d80debSLuiz Augusto von Dentz if (!hchan) 13040a708f8fSGustavo F. Padovan return NULL; 13050a708f8fSGustavo F. Padovan 130673d80debSLuiz Augusto von Dentz conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC); 130773d80debSLuiz Augusto von Dentz if (!conn) { 130873d80debSLuiz Augusto von Dentz hci_chan_del(hchan); 130973d80debSLuiz Augusto von Dentz return NULL; 131073d80debSLuiz Augusto von Dentz } 131173d80debSLuiz Augusto von Dentz 13120a708f8fSGustavo F. Padovan hcon->l2cap_data = conn; 13130a708f8fSGustavo F. Padovan conn->hcon = hcon; 131473d80debSLuiz Augusto von Dentz conn->hchan = hchan; 13150a708f8fSGustavo F. Padovan 131673d80debSLuiz Augusto von Dentz BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan); 13170a708f8fSGustavo F. Padovan 1318acd7d370SVille Tervo if (hcon->hdev->le_mtu && hcon->type == LE_LINK) 1319acd7d370SVille Tervo conn->mtu = hcon->hdev->le_mtu; 1320acd7d370SVille Tervo else 13210a708f8fSGustavo F. Padovan conn->mtu = hcon->hdev->acl_mtu; 1322acd7d370SVille Tervo 13230a708f8fSGustavo F. Padovan conn->src = &hcon->hdev->bdaddr; 13240a708f8fSGustavo F. Padovan conn->dst = &hcon->dst; 13250a708f8fSGustavo F. Padovan 13260a708f8fSGustavo F. Padovan conn->feat_mask = 0; 13270a708f8fSGustavo F. Padovan 13280a708f8fSGustavo F. Padovan spin_lock_init(&conn->lock); 13293df91ea2SAndrei Emeltchenko mutex_init(&conn->chan_lock); 1330baa7e1faSGustavo F. Padovan 1331baa7e1faSGustavo F. Padovan INIT_LIST_HEAD(&conn->chan_l); 13320a708f8fSGustavo F. Padovan 13335d3de7dfSVinicius Costa Gomes if (hcon->type == LE_LINK) 13346c9d42a1SGustavo F. Padovan INIT_DELAYED_WORK(&conn->security_timer, security_timeout); 13355d3de7dfSVinicius Costa Gomes else 1336030013d8SGustavo F. Padovan INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout); 13370a708f8fSGustavo F. Padovan 13389f5a0d7bSAndrei Emeltchenko conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; 13390a708f8fSGustavo F. Padovan 13400a708f8fSGustavo F. Padovan return conn; 13410a708f8fSGustavo F. Padovan } 13420a708f8fSGustavo F. Padovan 13430a708f8fSGustavo F. Padovan /* ---- Socket interface ---- */ 13440a708f8fSGustavo F. Padovan 1345c2287681SIdo Yariv /* Find socket with psm and source / destination bdaddr. 13460a708f8fSGustavo F. Padovan * Returns closest match. 13470a708f8fSGustavo F. Padovan */ 1348c2287681SIdo Yariv static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, 1349c2287681SIdo Yariv bdaddr_t *src, 1350c2287681SIdo Yariv bdaddr_t *dst) 13510a708f8fSGustavo F. Padovan { 135223691d75SGustavo F. Padovan struct l2cap_chan *c, *c1 = NULL; 13530a708f8fSGustavo F. Padovan 135423691d75SGustavo F. Padovan read_lock(&chan_list_lock); 13550a708f8fSGustavo F. Padovan 135623691d75SGustavo F. Padovan list_for_each_entry(c, &chan_list, global_l) { 135723691d75SGustavo F. Padovan struct sock *sk = c->sk; 1358fe4128e0SGustavo F. Padovan 135989bc500eSGustavo F. Padovan if (state && c->state != state) 13600a708f8fSGustavo F. Padovan continue; 13610a708f8fSGustavo F. Padovan 136223691d75SGustavo F. Padovan if (c->psm == psm) { 1363c2287681SIdo Yariv int src_match, dst_match; 1364c2287681SIdo Yariv int src_any, dst_any; 1365c2287681SIdo Yariv 13660a708f8fSGustavo F. Padovan /* Exact match. */ 1367c2287681SIdo Yariv src_match = !bacmp(&bt_sk(sk)->src, src); 1368c2287681SIdo Yariv dst_match = !bacmp(&bt_sk(sk)->dst, dst); 1369c2287681SIdo Yariv if (src_match && dst_match) { 1370a7567b20SJohannes Berg read_unlock(&chan_list_lock); 137123691d75SGustavo F. Padovan return c; 137223691d75SGustavo F. Padovan } 13730a708f8fSGustavo F. Padovan 13740a708f8fSGustavo F. Padovan /* Closest match */ 1375c2287681SIdo Yariv src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY); 1376c2287681SIdo Yariv dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY); 1377c2287681SIdo Yariv if ((src_match && dst_any) || (src_any && dst_match) || 1378c2287681SIdo Yariv (src_any && dst_any)) 137923691d75SGustavo F. Padovan c1 = c; 13800a708f8fSGustavo F. Padovan } 13810a708f8fSGustavo F. Padovan } 13820a708f8fSGustavo F. Padovan 138323691d75SGustavo F. Padovan read_unlock(&chan_list_lock); 13840a708f8fSGustavo F. Padovan 138523691d75SGustavo F. Padovan return c1; 13860a708f8fSGustavo F. Padovan } 13870a708f8fSGustavo F. Padovan 13888e9f9892SAndre Guedes int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, 13898e9f9892SAndre Guedes bdaddr_t *dst, u8 dst_type) 13900a708f8fSGustavo F. Padovan { 13915d41ce1dSGustavo F. Padovan struct sock *sk = chan->sk; 13920a708f8fSGustavo F. Padovan bdaddr_t *src = &bt_sk(sk)->src; 13930a708f8fSGustavo F. Padovan struct l2cap_conn *conn; 13940a708f8fSGustavo F. Padovan struct hci_conn *hcon; 13950a708f8fSGustavo F. Padovan struct hci_dev *hdev; 13960a708f8fSGustavo F. Padovan __u8 auth_type; 13970a708f8fSGustavo F. Padovan int err; 13980a708f8fSGustavo F. Padovan 13998e9f9892SAndre Guedes BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst), 14008e9f9892SAndre Guedes dst_type, __le16_to_cpu(chan->psm)); 14010a708f8fSGustavo F. Padovan 14020a708f8fSGustavo F. Padovan hdev = hci_get_route(dst, src); 14030a708f8fSGustavo F. Padovan if (!hdev) 14040a708f8fSGustavo F. Padovan return -EHOSTUNREACH; 14050a708f8fSGustavo F. Padovan 140609fd0de5SGustavo F. Padovan hci_dev_lock(hdev); 14070a708f8fSGustavo F. Padovan 14086be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 140903a00194SGustavo F. Padovan 141003a00194SGustavo F. Padovan /* PSM must be odd and lsb of upper byte must be 0 */ 141103a00194SGustavo F. Padovan if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid && 141203a00194SGustavo F. Padovan chan->chan_type != L2CAP_CHAN_RAW) { 141303a00194SGustavo F. Padovan err = -EINVAL; 141403a00194SGustavo F. Padovan goto done; 141503a00194SGustavo F. Padovan } 141603a00194SGustavo F. Padovan 141703a00194SGustavo F. Padovan if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) { 141803a00194SGustavo F. Padovan err = -EINVAL; 141903a00194SGustavo F. Padovan goto done; 142003a00194SGustavo F. Padovan } 142103a00194SGustavo F. Padovan 142203a00194SGustavo F. Padovan switch (chan->mode) { 142303a00194SGustavo F. Padovan case L2CAP_MODE_BASIC: 142403a00194SGustavo F. Padovan break; 142503a00194SGustavo F. Padovan case L2CAP_MODE_ERTM: 142603a00194SGustavo F. Padovan case L2CAP_MODE_STREAMING: 142703a00194SGustavo F. Padovan if (!disable_ertm) 142803a00194SGustavo F. Padovan break; 142903a00194SGustavo F. Padovan /* fall through */ 143003a00194SGustavo F. Padovan default: 143103a00194SGustavo F. Padovan err = -ENOTSUPP; 143203a00194SGustavo F. Padovan goto done; 143303a00194SGustavo F. Padovan } 143403a00194SGustavo F. Padovan 14356be36555SAndrei Emeltchenko lock_sock(sk); 14366be36555SAndrei Emeltchenko 143703a00194SGustavo F. Padovan switch (sk->sk_state) { 143803a00194SGustavo F. Padovan case BT_CONNECT: 143903a00194SGustavo F. Padovan case BT_CONNECT2: 144003a00194SGustavo F. Padovan case BT_CONFIG: 144103a00194SGustavo F. Padovan /* Already connecting */ 144203a00194SGustavo F. Padovan err = 0; 14436be36555SAndrei Emeltchenko release_sock(sk); 144403a00194SGustavo F. Padovan goto done; 144503a00194SGustavo F. Padovan 144603a00194SGustavo F. Padovan case BT_CONNECTED: 144703a00194SGustavo F. Padovan /* Already connected */ 144803a00194SGustavo F. Padovan err = -EISCONN; 14496be36555SAndrei Emeltchenko release_sock(sk); 145003a00194SGustavo F. Padovan goto done; 145103a00194SGustavo F. Padovan 145203a00194SGustavo F. Padovan case BT_OPEN: 145303a00194SGustavo F. Padovan case BT_BOUND: 145403a00194SGustavo F. Padovan /* Can connect */ 145503a00194SGustavo F. Padovan break; 145603a00194SGustavo F. Padovan 145703a00194SGustavo F. Padovan default: 145803a00194SGustavo F. Padovan err = -EBADFD; 14596be36555SAndrei Emeltchenko release_sock(sk); 146003a00194SGustavo F. Padovan goto done; 146103a00194SGustavo F. Padovan } 146203a00194SGustavo F. Padovan 146303a00194SGustavo F. Padovan /* Set destination address and psm */ 14649219b2a0SGustavo F. Padovan bacpy(&bt_sk(sk)->dst, dst); 14656be36555SAndrei Emeltchenko 14666be36555SAndrei Emeltchenko release_sock(sk); 14676be36555SAndrei Emeltchenko 146803a00194SGustavo F. Padovan chan->psm = psm; 146903a00194SGustavo F. Padovan chan->dcid = cid; 14700a708f8fSGustavo F. Padovan 14714343478fSGustavo F. Padovan auth_type = l2cap_get_auth_type(chan); 14720a708f8fSGustavo F. Padovan 1473fe4128e0SGustavo F. Padovan if (chan->dcid == L2CAP_CID_LE_DATA) 14748e9f9892SAndre Guedes hcon = hci_connect(hdev, LE_LINK, dst, dst_type, 14754343478fSGustavo F. Padovan chan->sec_level, auth_type); 1476acd7d370SVille Tervo else 14778e9f9892SAndre Guedes hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, 14784343478fSGustavo F. Padovan chan->sec_level, auth_type); 1479acd7d370SVille Tervo 148030e76272SVille Tervo if (IS_ERR(hcon)) { 148130e76272SVille Tervo err = PTR_ERR(hcon); 14820a708f8fSGustavo F. Padovan goto done; 148330e76272SVille Tervo } 14840a708f8fSGustavo F. Padovan 14850a708f8fSGustavo F. Padovan conn = l2cap_conn_add(hcon, 0); 14860a708f8fSGustavo F. Padovan if (!conn) { 14870a708f8fSGustavo F. Padovan hci_conn_put(hcon); 148830e76272SVille Tervo err = -ENOMEM; 14890a708f8fSGustavo F. Padovan goto done; 14900a708f8fSGustavo F. Padovan } 14910a708f8fSGustavo F. Padovan 14929f0caeb1SVinicius Costa Gomes if (hcon->type == LE_LINK) { 14939f0caeb1SVinicius Costa Gomes err = 0; 14949f0caeb1SVinicius Costa Gomes 14959f0caeb1SVinicius Costa Gomes if (!list_empty(&conn->chan_l)) { 14969f0caeb1SVinicius Costa Gomes err = -EBUSY; 14979f0caeb1SVinicius Costa Gomes hci_conn_put(hcon); 14989f0caeb1SVinicius Costa Gomes } 14999f0caeb1SVinicius Costa Gomes 15009f0caeb1SVinicius Costa Gomes if (err) 15019f0caeb1SVinicius Costa Gomes goto done; 15029f0caeb1SVinicius Costa Gomes } 15039f0caeb1SVinicius Costa Gomes 15040a708f8fSGustavo F. Padovan /* Update source addr of the socket */ 15050a708f8fSGustavo F. Padovan bacpy(src, conn->src); 15060a708f8fSGustavo F. Padovan 15076be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 150848454079SGustavo F. Padovan l2cap_chan_add(conn, chan); 15096be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 151048454079SGustavo F. Padovan 15116be36555SAndrei Emeltchenko l2cap_state_change(chan, BT_CONNECT); 1512c9b66675SGustavo F. Padovan __set_chan_timer(chan, sk->sk_sndtimeo); 15130a708f8fSGustavo F. Padovan 15140a708f8fSGustavo F. Padovan if (hcon->state == BT_CONNECTED) { 1515715ec005SGustavo F. Padovan if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) { 1516c9b66675SGustavo F. Padovan __clear_chan_timer(chan); 1517d45fc423SGustavo F. Padovan if (l2cap_chan_check_security(chan)) 15186be36555SAndrei Emeltchenko l2cap_state_change(chan, BT_CONNECTED); 15190a708f8fSGustavo F. Padovan } else 1520fc7f8a7eSGustavo F. Padovan l2cap_do_start(chan); 15210a708f8fSGustavo F. Padovan } 15220a708f8fSGustavo F. Padovan 152330e76272SVille Tervo err = 0; 152430e76272SVille Tervo 15250a708f8fSGustavo F. Padovan done: 15266be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 152709fd0de5SGustavo F. Padovan hci_dev_unlock(hdev); 15280a708f8fSGustavo F. Padovan hci_dev_put(hdev); 15290a708f8fSGustavo F. Padovan return err; 15300a708f8fSGustavo F. Padovan } 15310a708f8fSGustavo F. Padovan 1532dcba0dbaSGustavo F. Padovan int __l2cap_wait_ack(struct sock *sk) 15330a708f8fSGustavo F. Padovan { 15348c1d787bSGustavo F. Padovan struct l2cap_chan *chan = l2cap_pi(sk)->chan; 15350a708f8fSGustavo F. Padovan DECLARE_WAITQUEUE(wait, current); 15360a708f8fSGustavo F. Padovan int err = 0; 15370a708f8fSGustavo F. Padovan int timeo = HZ/5; 15380a708f8fSGustavo F. Padovan 15390a708f8fSGustavo F. Padovan add_wait_queue(sk_sleep(sk), &wait); 15400a708f8fSGustavo F. Padovan set_current_state(TASK_INTERRUPTIBLE); 1541a71a0cf4SPeter Hurley while (chan->unacked_frames > 0 && chan->conn) { 15420a708f8fSGustavo F. Padovan if (!timeo) 15430a708f8fSGustavo F. Padovan timeo = HZ/5; 15440a708f8fSGustavo F. Padovan 15450a708f8fSGustavo F. Padovan if (signal_pending(current)) { 15460a708f8fSGustavo F. Padovan err = sock_intr_errno(timeo); 15470a708f8fSGustavo F. Padovan break; 15480a708f8fSGustavo F. Padovan } 15490a708f8fSGustavo F. Padovan 15500a708f8fSGustavo F. Padovan release_sock(sk); 15510a708f8fSGustavo F. Padovan timeo = schedule_timeout(timeo); 15520a708f8fSGustavo F. Padovan lock_sock(sk); 1553a71a0cf4SPeter Hurley set_current_state(TASK_INTERRUPTIBLE); 15540a708f8fSGustavo F. Padovan 15550a708f8fSGustavo F. Padovan err = sock_error(sk); 15560a708f8fSGustavo F. Padovan if (err) 15570a708f8fSGustavo F. Padovan break; 15580a708f8fSGustavo F. Padovan } 15590a708f8fSGustavo F. Padovan set_current_state(TASK_RUNNING); 15600a708f8fSGustavo F. Padovan remove_wait_queue(sk_sleep(sk), &wait); 15610a708f8fSGustavo F. Padovan return err; 15620a708f8fSGustavo F. Padovan } 15630a708f8fSGustavo F. Padovan 1564721c4181SGustavo F. Padovan static void l2cap_monitor_timeout(struct work_struct *work) 15650a708f8fSGustavo F. Padovan { 1566721c4181SGustavo F. Padovan struct l2cap_chan *chan = container_of(work, struct l2cap_chan, 1567721c4181SGustavo F. Padovan monitor_timer.work); 15680a708f8fSGustavo F. Padovan 1569525cd185SGustavo F. Padovan BT_DBG("chan %p", chan); 15700a708f8fSGustavo F. Padovan 15716be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 15726be36555SAndrei Emeltchenko 15732c03a7a4SGustavo F. Padovan if (chan->retry_count >= chan->remote_max_tx) { 15748c1d787bSGustavo F. Padovan l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); 15756be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 15768d7e1c7fSAndrei Emeltchenko l2cap_chan_put(chan); 15770a708f8fSGustavo F. Padovan return; 15780a708f8fSGustavo F. Padovan } 15790a708f8fSGustavo F. Padovan 15806a026610SGustavo F. Padovan chan->retry_count++; 15811a09bcb9SGustavo F. Padovan __set_monitor_timer(chan); 15820a708f8fSGustavo F. Padovan 1583525cd185SGustavo F. Padovan l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); 15846be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 15858d7e1c7fSAndrei Emeltchenko l2cap_chan_put(chan); 15860a708f8fSGustavo F. Padovan } 15870a708f8fSGustavo F. Padovan 1588721c4181SGustavo F. Padovan static void l2cap_retrans_timeout(struct work_struct *work) 15890a708f8fSGustavo F. Padovan { 1590721c4181SGustavo F. Padovan struct l2cap_chan *chan = container_of(work, struct l2cap_chan, 1591721c4181SGustavo F. Padovan retrans_timer.work); 15920a708f8fSGustavo F. Padovan 159349208c9cSGustavo F. Padovan BT_DBG("chan %p", chan); 15940a708f8fSGustavo F. Padovan 15956be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 15966be36555SAndrei Emeltchenko 15976a026610SGustavo F. Padovan chan->retry_count = 1; 15981a09bcb9SGustavo F. Padovan __set_monitor_timer(chan); 15990a708f8fSGustavo F. Padovan 1600e2ab4353SGustavo F. Padovan set_bit(CONN_WAIT_F, &chan->conn_state); 16010a708f8fSGustavo F. Padovan 1602525cd185SGustavo F. Padovan l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); 16036be36555SAndrei Emeltchenko 16046be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 16058d7e1c7fSAndrei Emeltchenko l2cap_chan_put(chan); 16060a708f8fSGustavo F. Padovan } 16070a708f8fSGustavo F. Padovan 160842e5c802SGustavo F. Padovan static void l2cap_drop_acked_frames(struct l2cap_chan *chan) 16090a708f8fSGustavo F. Padovan { 16100a708f8fSGustavo F. Padovan struct sk_buff *skb; 16110a708f8fSGustavo F. Padovan 161258d35f87SGustavo F. Padovan while ((skb = skb_peek(&chan->tx_q)) && 16136a026610SGustavo F. Padovan chan->unacked_frames) { 16143ce3514fSMat Martineau if (bt_cb(skb)->control.txseq == chan->expected_ack_seq) 16150a708f8fSGustavo F. Padovan break; 16160a708f8fSGustavo F. Padovan 161758d35f87SGustavo F. Padovan skb = skb_dequeue(&chan->tx_q); 16180a708f8fSGustavo F. Padovan kfree_skb(skb); 16190a708f8fSGustavo F. Padovan 16206a026610SGustavo F. Padovan chan->unacked_frames--; 16210a708f8fSGustavo F. Padovan } 16220a708f8fSGustavo F. Padovan 16236a026610SGustavo F. Padovan if (!chan->unacked_frames) 16241a09bcb9SGustavo F. Padovan __clear_retrans_timer(chan); 16250a708f8fSGustavo F. Padovan } 16260a708f8fSGustavo F. Padovan 162767c9e840SSzymon Janc static void l2cap_streaming_send(struct l2cap_chan *chan) 16280a708f8fSGustavo F. Padovan { 16290a708f8fSGustavo F. Padovan struct sk_buff *skb; 163088843ab0SAndrei Emeltchenko u32 control; 163188843ab0SAndrei Emeltchenko u16 fcs; 16320a708f8fSGustavo F. Padovan 163358d35f87SGustavo F. Padovan while ((skb = skb_dequeue(&chan->tx_q))) { 163488843ab0SAndrei Emeltchenko control = __get_control(chan, skb->data + L2CAP_HDR_SIZE); 1635fb45de7dSAndrei Emeltchenko control |= __set_txseq(chan, chan->next_tx_seq); 163688843ab0SAndrei Emeltchenko __put_control(chan, control, skb->data + L2CAP_HDR_SIZE); 16370a708f8fSGustavo F. Padovan 163847d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_CRC16) { 163903a51213SAndrei Emeltchenko fcs = crc16(0, (u8 *)skb->data, 164003a51213SAndrei Emeltchenko skb->len - L2CAP_FCS_SIZE); 164103a51213SAndrei Emeltchenko put_unaligned_le16(fcs, 164203a51213SAndrei Emeltchenko skb->data + skb->len - L2CAP_FCS_SIZE); 16430a708f8fSGustavo F. Padovan } 16440a708f8fSGustavo F. Padovan 16454343478fSGustavo F. Padovan l2cap_do_send(chan, skb); 16460a708f8fSGustavo F. Padovan 1647836be934SAndrei Emeltchenko chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); 16480a708f8fSGustavo F. Padovan } 16490a708f8fSGustavo F. Padovan } 16500a708f8fSGustavo F. Padovan 1651fb45de7dSAndrei Emeltchenko static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq) 16520a708f8fSGustavo F. Padovan { 16530a708f8fSGustavo F. Padovan struct sk_buff *skb, *tx_skb; 165488843ab0SAndrei Emeltchenko u16 fcs; 165588843ab0SAndrei Emeltchenko u32 control; 16560a708f8fSGustavo F. Padovan 165758d35f87SGustavo F. Padovan skb = skb_peek(&chan->tx_q); 16580a708f8fSGustavo F. Padovan if (!skb) 16590a708f8fSGustavo F. Padovan return; 16600a708f8fSGustavo F. Padovan 16613ce3514fSMat Martineau while (bt_cb(skb)->control.txseq != tx_seq) { 166258d35f87SGustavo F. Padovan if (skb_queue_is_last(&chan->tx_q, skb)) 16630a708f8fSGustavo F. Padovan return; 16640a708f8fSGustavo F. Padovan 1665d1726b6dSSzymon Janc skb = skb_queue_next(&chan->tx_q, skb); 1666d1726b6dSSzymon Janc } 16670a708f8fSGustavo F. Padovan 16683ce3514fSMat Martineau if (bt_cb(skb)->control.retries == chan->remote_max_tx && 16693ce3514fSMat Martineau chan->remote_max_tx) { 16708c1d787bSGustavo F. Padovan l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); 16710a708f8fSGustavo F. Padovan return; 16720a708f8fSGustavo F. Padovan } 16730a708f8fSGustavo F. Padovan 16740a708f8fSGustavo F. Padovan tx_skb = skb_clone(skb, GFP_ATOMIC); 16753ce3514fSMat Martineau bt_cb(skb)->control.retries++; 167688843ab0SAndrei Emeltchenko 167788843ab0SAndrei Emeltchenko control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); 16787e0ef6eeSAndrei Emeltchenko control &= __get_sar_mask(chan); 16790a708f8fSGustavo F. Padovan 1680e2ab4353SGustavo F. Padovan if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) 168103f6715dSAndrei Emeltchenko control |= __set_ctrl_final(chan); 16820a708f8fSGustavo F. Padovan 16830b209faeSAndrei Emeltchenko control |= __set_reqseq(chan, chan->buffer_seq); 1684fb45de7dSAndrei Emeltchenko control |= __set_txseq(chan, tx_seq); 16850a708f8fSGustavo F. Padovan 168688843ab0SAndrei Emeltchenko __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); 16870a708f8fSGustavo F. Padovan 168847d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_CRC16) { 168903a51213SAndrei Emeltchenko fcs = crc16(0, (u8 *)tx_skb->data, 169003a51213SAndrei Emeltchenko tx_skb->len - L2CAP_FCS_SIZE); 169103a51213SAndrei Emeltchenko put_unaligned_le16(fcs, 169203a51213SAndrei Emeltchenko tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE); 16930a708f8fSGustavo F. Padovan } 16940a708f8fSGustavo F. Padovan 16954343478fSGustavo F. Padovan l2cap_do_send(chan, tx_skb); 16960a708f8fSGustavo F. Padovan } 16970a708f8fSGustavo F. Padovan 169867c9e840SSzymon Janc static int l2cap_ertm_send(struct l2cap_chan *chan) 16990a708f8fSGustavo F. Padovan { 17000a708f8fSGustavo F. Padovan struct sk_buff *skb, *tx_skb; 170188843ab0SAndrei Emeltchenko u16 fcs; 170288843ab0SAndrei Emeltchenko u32 control; 17030a708f8fSGustavo F. Padovan int nsent = 0; 17040a708f8fSGustavo F. Padovan 170589bc500eSGustavo F. Padovan if (chan->state != BT_CONNECTED) 17060a708f8fSGustavo F. Padovan return -ENOTCONN; 17070a708f8fSGustavo F. Padovan 170858d35f87SGustavo F. Padovan while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { 17090a708f8fSGustavo F. Padovan 17103ce3514fSMat Martineau if (bt_cb(skb)->control.retries == chan->remote_max_tx && 17113ce3514fSMat Martineau chan->remote_max_tx) { 17128c1d787bSGustavo F. Padovan l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); 17130a708f8fSGustavo F. Padovan break; 17140a708f8fSGustavo F. Padovan } 17150a708f8fSGustavo F. Padovan 17160a708f8fSGustavo F. Padovan tx_skb = skb_clone(skb, GFP_ATOMIC); 17170a708f8fSGustavo F. Padovan 17183ce3514fSMat Martineau bt_cb(skb)->control.retries++; 17190a708f8fSGustavo F. Padovan 172088843ab0SAndrei Emeltchenko control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); 17217e0ef6eeSAndrei Emeltchenko control &= __get_sar_mask(chan); 17220a708f8fSGustavo F. Padovan 1723e2ab4353SGustavo F. Padovan if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) 172403f6715dSAndrei Emeltchenko control |= __set_ctrl_final(chan); 1725e2ab4353SGustavo F. Padovan 17260b209faeSAndrei Emeltchenko control |= __set_reqseq(chan, chan->buffer_seq); 1727fb45de7dSAndrei Emeltchenko control |= __set_txseq(chan, chan->next_tx_seq); 17280a708f8fSGustavo F. Padovan 172988843ab0SAndrei Emeltchenko __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); 17300a708f8fSGustavo F. Padovan 173147d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_CRC16) { 173203a51213SAndrei Emeltchenko fcs = crc16(0, (u8 *)skb->data, 173303a51213SAndrei Emeltchenko tx_skb->len - L2CAP_FCS_SIZE); 173403a51213SAndrei Emeltchenko put_unaligned_le16(fcs, skb->data + 173503a51213SAndrei Emeltchenko tx_skb->len - L2CAP_FCS_SIZE); 17360a708f8fSGustavo F. Padovan } 17370a708f8fSGustavo F. Padovan 17384343478fSGustavo F. Padovan l2cap_do_send(chan, tx_skb); 17390a708f8fSGustavo F. Padovan 17401a09bcb9SGustavo F. Padovan __set_retrans_timer(chan); 17410a708f8fSGustavo F. Padovan 17423ce3514fSMat Martineau bt_cb(skb)->control.txseq = chan->next_tx_seq; 1743836be934SAndrei Emeltchenko 1744836be934SAndrei Emeltchenko chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); 17450a708f8fSGustavo F. Padovan 17463ce3514fSMat Martineau if (bt_cb(skb)->control.retries == 1) { 17476a026610SGustavo F. Padovan chan->unacked_frames++; 1748930fa4aeSSzymon Janc 1749930fa4aeSSzymon Janc if (!nsent++) 1750930fa4aeSSzymon Janc __clear_ack_timer(chan); 17518ed7a0aeSSzymon Janc } 175223e9fde2SSuraj Sumangala 17536a026610SGustavo F. Padovan chan->frames_sent++; 17540a708f8fSGustavo F. Padovan 175558d35f87SGustavo F. Padovan if (skb_queue_is_last(&chan->tx_q, skb)) 175658d35f87SGustavo F. Padovan chan->tx_send_head = NULL; 17570a708f8fSGustavo F. Padovan else 175858d35f87SGustavo F. Padovan chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); 17590a708f8fSGustavo F. Padovan } 17600a708f8fSGustavo F. Padovan 17610a708f8fSGustavo F. Padovan return nsent; 17620a708f8fSGustavo F. Padovan } 17630a708f8fSGustavo F. Padovan 1764525cd185SGustavo F. Padovan static int l2cap_retransmit_frames(struct l2cap_chan *chan) 17650a708f8fSGustavo F. Padovan { 17660a708f8fSGustavo F. Padovan int ret; 17670a708f8fSGustavo F. Padovan 176858d35f87SGustavo F. Padovan if (!skb_queue_empty(&chan->tx_q)) 176958d35f87SGustavo F. Padovan chan->tx_send_head = chan->tx_q.next; 17700a708f8fSGustavo F. Padovan 177142e5c802SGustavo F. Padovan chan->next_tx_seq = chan->expected_ack_seq; 1772525cd185SGustavo F. Padovan ret = l2cap_ertm_send(chan); 17730a708f8fSGustavo F. Padovan return ret; 17740a708f8fSGustavo F. Padovan } 17750a708f8fSGustavo F. Padovan 1776b17e73bbSSzymon Janc static void __l2cap_send_ack(struct l2cap_chan *chan) 17770a708f8fSGustavo F. Padovan { 177888843ab0SAndrei Emeltchenko u32 control = 0; 17790a708f8fSGustavo F. Padovan 17800b209faeSAndrei Emeltchenko control |= __set_reqseq(chan, chan->buffer_seq); 17810a708f8fSGustavo F. Padovan 1782e2ab4353SGustavo F. Padovan if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { 1783ab784b73SAndrei Emeltchenko control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); 1784e2ab4353SGustavo F. Padovan set_bit(CONN_RNR_SENT, &chan->conn_state); 1785525cd185SGustavo F. Padovan l2cap_send_sframe(chan, control); 17860a708f8fSGustavo F. Padovan return; 17870a708f8fSGustavo F. Padovan } 17880a708f8fSGustavo F. Padovan 1789525cd185SGustavo F. Padovan if (l2cap_ertm_send(chan) > 0) 17900a708f8fSGustavo F. Padovan return; 17910a708f8fSGustavo F. Padovan 1792ab784b73SAndrei Emeltchenko control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); 1793525cd185SGustavo F. Padovan l2cap_send_sframe(chan, control); 17940a708f8fSGustavo F. Padovan } 17950a708f8fSGustavo F. Padovan 1796b17e73bbSSzymon Janc static void l2cap_send_ack(struct l2cap_chan *chan) 1797b17e73bbSSzymon Janc { 1798b17e73bbSSzymon Janc __clear_ack_timer(chan); 1799b17e73bbSSzymon Janc __l2cap_send_ack(chan); 1800b17e73bbSSzymon Janc } 1801b17e73bbSSzymon Janc 1802525cd185SGustavo F. Padovan static void l2cap_send_srejtail(struct l2cap_chan *chan) 18030a708f8fSGustavo F. Padovan { 18040a708f8fSGustavo F. Padovan struct srej_list *tail; 180588843ab0SAndrei Emeltchenko u32 control; 18060a708f8fSGustavo F. Padovan 1807ab784b73SAndrei Emeltchenko control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); 180803f6715dSAndrei Emeltchenko control |= __set_ctrl_final(chan); 18090a708f8fSGustavo F. Padovan 181039d5a3eeSGustavo F. Padovan tail = list_entry((&chan->srej_l)->prev, struct srej_list, list); 18110b209faeSAndrei Emeltchenko control |= __set_reqseq(chan, tail->tx_seq); 18120a708f8fSGustavo F. Padovan 1813525cd185SGustavo F. Padovan l2cap_send_sframe(chan, control); 18140a708f8fSGustavo F. Padovan } 18150a708f8fSGustavo F. Padovan 181604124681SGustavo F. Padovan static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, 181704124681SGustavo F. Padovan struct msghdr *msg, int len, 181804124681SGustavo F. Padovan int count, struct sk_buff *skb) 18190a708f8fSGustavo F. Padovan { 18200952a57aSAndrei Emeltchenko struct l2cap_conn *conn = chan->conn; 18210a708f8fSGustavo F. Padovan struct sk_buff **frag; 182290338947SGustavo Padovan int sent = 0; 18230a708f8fSGustavo F. Padovan 18240a708f8fSGustavo F. Padovan if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) 18250a708f8fSGustavo F. Padovan return -EFAULT; 18260a708f8fSGustavo F. Padovan 18270a708f8fSGustavo F. Padovan sent += count; 18280a708f8fSGustavo F. Padovan len -= count; 18290a708f8fSGustavo F. Padovan 18300a708f8fSGustavo F. Padovan /* Continuation fragments (no L2CAP header) */ 18310a708f8fSGustavo F. Padovan frag = &skb_shinfo(skb)->frag_list; 18320a708f8fSGustavo F. Padovan while (len) { 18330a708f8fSGustavo F. Padovan count = min_t(unsigned int, conn->mtu, len); 18340a708f8fSGustavo F. Padovan 18352f7719ceSAndrei Emeltchenko *frag = chan->ops->alloc_skb(chan, count, 183690338947SGustavo Padovan msg->msg_flags & MSG_DONTWAIT); 18372f7719ceSAndrei Emeltchenko 183890338947SGustavo Padovan if (IS_ERR(*frag)) 183990338947SGustavo Padovan return PTR_ERR(*frag); 18400a708f8fSGustavo F. Padovan if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) 18410a708f8fSGustavo F. Padovan return -EFAULT; 18420a708f8fSGustavo F. Padovan 18435e59b791SLuiz Augusto von Dentz (*frag)->priority = skb->priority; 18445e59b791SLuiz Augusto von Dentz 18450a708f8fSGustavo F. Padovan sent += count; 18460a708f8fSGustavo F. Padovan len -= count; 18470a708f8fSGustavo F. Padovan 18480a708f8fSGustavo F. Padovan frag = &(*frag)->next; 18490a708f8fSGustavo F. Padovan } 18500a708f8fSGustavo F. Padovan 18510a708f8fSGustavo F. Padovan return sent; 18520a708f8fSGustavo F. Padovan } 18530a708f8fSGustavo F. Padovan 18545e59b791SLuiz Augusto von Dentz static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, 18555e59b791SLuiz Augusto von Dentz struct msghdr *msg, size_t len, 18565e59b791SLuiz Augusto von Dentz u32 priority) 18570a708f8fSGustavo F. Padovan { 18588c1d787bSGustavo F. Padovan struct l2cap_conn *conn = chan->conn; 18590a708f8fSGustavo F. Padovan struct sk_buff *skb; 186003a51213SAndrei Emeltchenko int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE; 18610a708f8fSGustavo F. Padovan struct l2cap_hdr *lh; 18620a708f8fSGustavo F. Padovan 18636d5922b0SAndrei Emeltchenko BT_DBG("chan %p len %d priority %u", chan, (int)len, priority); 18640a708f8fSGustavo F. Padovan 18650a708f8fSGustavo F. Padovan count = min_t(unsigned int, (conn->mtu - hlen), len); 18662f7719ceSAndrei Emeltchenko 18672f7719ceSAndrei Emeltchenko skb = chan->ops->alloc_skb(chan, count + hlen, 186890338947SGustavo Padovan msg->msg_flags & MSG_DONTWAIT); 186990338947SGustavo Padovan if (IS_ERR(skb)) 187090338947SGustavo Padovan return skb; 18710a708f8fSGustavo F. Padovan 18725e59b791SLuiz Augusto von Dentz skb->priority = priority; 18735e59b791SLuiz Augusto von Dentz 18740a708f8fSGustavo F. Padovan /* Create L2CAP header */ 18750a708f8fSGustavo F. Padovan lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); 1876fe4128e0SGustavo F. Padovan lh->cid = cpu_to_le16(chan->dcid); 18770a708f8fSGustavo F. Padovan lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); 1878097db76cSAndrei Emeltchenko put_unaligned(chan->psm, skb_put(skb, 2)); 18790a708f8fSGustavo F. Padovan 18800952a57aSAndrei Emeltchenko err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); 18810a708f8fSGustavo F. Padovan if (unlikely(err < 0)) { 18820a708f8fSGustavo F. Padovan kfree_skb(skb); 18830a708f8fSGustavo F. Padovan return ERR_PTR(err); 18840a708f8fSGustavo F. Padovan } 18850a708f8fSGustavo F. Padovan return skb; 18860a708f8fSGustavo F. Padovan } 18870a708f8fSGustavo F. Padovan 18885e59b791SLuiz Augusto von Dentz static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, 18895e59b791SLuiz Augusto von Dentz struct msghdr *msg, size_t len, 18905e59b791SLuiz Augusto von Dentz u32 priority) 18910a708f8fSGustavo F. Padovan { 18928c1d787bSGustavo F. Padovan struct l2cap_conn *conn = chan->conn; 18930a708f8fSGustavo F. Padovan struct sk_buff *skb; 18940a708f8fSGustavo F. Padovan int err, count, hlen = L2CAP_HDR_SIZE; 18950a708f8fSGustavo F. Padovan struct l2cap_hdr *lh; 18960a708f8fSGustavo F. Padovan 18976d5922b0SAndrei Emeltchenko BT_DBG("chan %p len %d", chan, (int)len); 18980a708f8fSGustavo F. Padovan 18990a708f8fSGustavo F. Padovan count = min_t(unsigned int, (conn->mtu - hlen), len); 19002f7719ceSAndrei Emeltchenko 19012f7719ceSAndrei Emeltchenko skb = chan->ops->alloc_skb(chan, count + hlen, 190290338947SGustavo Padovan msg->msg_flags & MSG_DONTWAIT); 190390338947SGustavo Padovan if (IS_ERR(skb)) 190490338947SGustavo Padovan return skb; 19050a708f8fSGustavo F. Padovan 19065e59b791SLuiz Augusto von Dentz skb->priority = priority; 19075e59b791SLuiz Augusto von Dentz 19080a708f8fSGustavo F. Padovan /* Create L2CAP header */ 19090a708f8fSGustavo F. Padovan lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); 1910fe4128e0SGustavo F. Padovan lh->cid = cpu_to_le16(chan->dcid); 19110a708f8fSGustavo F. Padovan lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); 19120a708f8fSGustavo F. Padovan 19130952a57aSAndrei Emeltchenko err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); 19140a708f8fSGustavo F. Padovan if (unlikely(err < 0)) { 19150a708f8fSGustavo F. Padovan kfree_skb(skb); 19160a708f8fSGustavo F. Padovan return ERR_PTR(err); 19170a708f8fSGustavo F. Padovan } 19180a708f8fSGustavo F. Padovan return skb; 19190a708f8fSGustavo F. Padovan } 19200a708f8fSGustavo F. Padovan 1921ab0ff76dSLuiz Augusto von Dentz static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, 1922ab0ff76dSLuiz Augusto von Dentz struct msghdr *msg, size_t len, 192388843ab0SAndrei Emeltchenko u32 control, u16 sdulen) 19240a708f8fSGustavo F. Padovan { 19258c1d787bSGustavo F. Padovan struct l2cap_conn *conn = chan->conn; 19260a708f8fSGustavo F. Padovan struct sk_buff *skb; 1927e4ca6d98SAndrei Emeltchenko int err, count, hlen; 19280a708f8fSGustavo F. Padovan struct l2cap_hdr *lh; 19290a708f8fSGustavo F. Padovan 19306d5922b0SAndrei Emeltchenko BT_DBG("chan %p len %d", chan, (int)len); 19310a708f8fSGustavo F. Padovan 19320a708f8fSGustavo F. Padovan if (!conn) 19330a708f8fSGustavo F. Padovan return ERR_PTR(-ENOTCONN); 19340a708f8fSGustavo F. Padovan 1935e4ca6d98SAndrei Emeltchenko if (test_bit(FLAG_EXT_CTRL, &chan->flags)) 1936e4ca6d98SAndrei Emeltchenko hlen = L2CAP_EXT_HDR_SIZE; 1937e4ca6d98SAndrei Emeltchenko else 1938e4ca6d98SAndrei Emeltchenko hlen = L2CAP_ENH_HDR_SIZE; 1939e4ca6d98SAndrei Emeltchenko 19400a708f8fSGustavo F. Padovan if (sdulen) 194103a51213SAndrei Emeltchenko hlen += L2CAP_SDULEN_SIZE; 19420a708f8fSGustavo F. Padovan 194347d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_CRC16) 194403a51213SAndrei Emeltchenko hlen += L2CAP_FCS_SIZE; 19450a708f8fSGustavo F. Padovan 19460a708f8fSGustavo F. Padovan count = min_t(unsigned int, (conn->mtu - hlen), len); 19472f7719ceSAndrei Emeltchenko 19482f7719ceSAndrei Emeltchenko skb = chan->ops->alloc_skb(chan, count + hlen, 194990338947SGustavo Padovan msg->msg_flags & MSG_DONTWAIT); 195090338947SGustavo Padovan if (IS_ERR(skb)) 195190338947SGustavo Padovan return skb; 19520a708f8fSGustavo F. Padovan 19530a708f8fSGustavo F. Padovan /* Create L2CAP header */ 19540a708f8fSGustavo F. Padovan lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); 1955fe4128e0SGustavo F. Padovan lh->cid = cpu_to_le16(chan->dcid); 19560a708f8fSGustavo F. Padovan lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); 195788843ab0SAndrei Emeltchenko 195888843ab0SAndrei Emeltchenko __put_control(chan, control, skb_put(skb, __ctrl_size(chan))); 195988843ab0SAndrei Emeltchenko 19600a708f8fSGustavo F. Padovan if (sdulen) 196103a51213SAndrei Emeltchenko put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); 19620a708f8fSGustavo F. Padovan 19630952a57aSAndrei Emeltchenko err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); 19640a708f8fSGustavo F. Padovan if (unlikely(err < 0)) { 19650a708f8fSGustavo F. Padovan kfree_skb(skb); 19660a708f8fSGustavo F. Padovan return ERR_PTR(err); 19670a708f8fSGustavo F. Padovan } 19680a708f8fSGustavo F. Padovan 196947d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_CRC16) 197003a51213SAndrei Emeltchenko put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE)); 19710a708f8fSGustavo F. Padovan 19723ce3514fSMat Martineau bt_cb(skb)->control.retries = 0; 19730a708f8fSGustavo F. Padovan return skb; 19740a708f8fSGustavo F. Padovan } 19750a708f8fSGustavo F. Padovan 197667c9e840SSzymon Janc static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) 19770a708f8fSGustavo F. Padovan { 19780a708f8fSGustavo F. Padovan struct sk_buff *skb; 19790a708f8fSGustavo F. Padovan struct sk_buff_head sar_queue; 198088843ab0SAndrei Emeltchenko u32 control; 19810a708f8fSGustavo F. Padovan size_t size = 0; 19820a708f8fSGustavo F. Padovan 19830a708f8fSGustavo F. Padovan skb_queue_head_init(&sar_queue); 19847e0ef6eeSAndrei Emeltchenko control = __set_ctrl_sar(chan, L2CAP_SAR_START); 198547d1ec61SGustavo F. Padovan skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len); 19860a708f8fSGustavo F. Padovan if (IS_ERR(skb)) 19870a708f8fSGustavo F. Padovan return PTR_ERR(skb); 19880a708f8fSGustavo F. Padovan 19890a708f8fSGustavo F. Padovan __skb_queue_tail(&sar_queue, skb); 19902c03a7a4SGustavo F. Padovan len -= chan->remote_mps; 19912c03a7a4SGustavo F. Padovan size += chan->remote_mps; 19920a708f8fSGustavo F. Padovan 19930a708f8fSGustavo F. Padovan while (len > 0) { 19940a708f8fSGustavo F. Padovan size_t buflen; 19950a708f8fSGustavo F. Padovan 19962c03a7a4SGustavo F. Padovan if (len > chan->remote_mps) { 19977e0ef6eeSAndrei Emeltchenko control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE); 19982c03a7a4SGustavo F. Padovan buflen = chan->remote_mps; 19990a708f8fSGustavo F. Padovan } else { 20007e0ef6eeSAndrei Emeltchenko control = __set_ctrl_sar(chan, L2CAP_SAR_END); 20010a708f8fSGustavo F. Padovan buflen = len; 20020a708f8fSGustavo F. Padovan } 20030a708f8fSGustavo F. Padovan 200447d1ec61SGustavo F. Padovan skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0); 20050a708f8fSGustavo F. Padovan if (IS_ERR(skb)) { 20060a708f8fSGustavo F. Padovan skb_queue_purge(&sar_queue); 20070a708f8fSGustavo F. Padovan return PTR_ERR(skb); 20080a708f8fSGustavo F. Padovan } 20090a708f8fSGustavo F. Padovan 20100a708f8fSGustavo F. Padovan __skb_queue_tail(&sar_queue, skb); 20110a708f8fSGustavo F. Padovan len -= buflen; 20120a708f8fSGustavo F. Padovan size += buflen; 20130a708f8fSGustavo F. Padovan } 201458d35f87SGustavo F. Padovan skb_queue_splice_tail(&sar_queue, &chan->tx_q); 201558d35f87SGustavo F. Padovan if (chan->tx_send_head == NULL) 201658d35f87SGustavo F. Padovan chan->tx_send_head = sar_queue.next; 20170a708f8fSGustavo F. Padovan 20180a708f8fSGustavo F. Padovan return size; 20190a708f8fSGustavo F. Padovan } 20200a708f8fSGustavo F. Padovan 20215e59b791SLuiz Augusto von Dentz int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, 20225e59b791SLuiz Augusto von Dentz u32 priority) 20239a91a04aSGustavo F. Padovan { 20249a91a04aSGustavo F. Padovan struct sk_buff *skb; 202588843ab0SAndrei Emeltchenko u32 control; 20269a91a04aSGustavo F. Padovan int err; 20279a91a04aSGustavo F. Padovan 20289a91a04aSGustavo F. Padovan /* Connectionless channel */ 2029715ec005SGustavo F. Padovan if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { 20305e59b791SLuiz Augusto von Dentz skb = l2cap_create_connless_pdu(chan, msg, len, priority); 20319a91a04aSGustavo F. Padovan if (IS_ERR(skb)) 20329a91a04aSGustavo F. Padovan return PTR_ERR(skb); 20339a91a04aSGustavo F. Padovan 20349a91a04aSGustavo F. Padovan l2cap_do_send(chan, skb); 20359a91a04aSGustavo F. Padovan return len; 20369a91a04aSGustavo F. Padovan } 20379a91a04aSGustavo F. Padovan 20389a91a04aSGustavo F. Padovan switch (chan->mode) { 20399a91a04aSGustavo F. Padovan case L2CAP_MODE_BASIC: 20409a91a04aSGustavo F. Padovan /* Check outgoing MTU */ 20419a91a04aSGustavo F. Padovan if (len > chan->omtu) 20429a91a04aSGustavo F. Padovan return -EMSGSIZE; 20439a91a04aSGustavo F. Padovan 20449a91a04aSGustavo F. Padovan /* Create a basic PDU */ 20455e59b791SLuiz Augusto von Dentz skb = l2cap_create_basic_pdu(chan, msg, len, priority); 20469a91a04aSGustavo F. Padovan if (IS_ERR(skb)) 20479a91a04aSGustavo F. Padovan return PTR_ERR(skb); 20489a91a04aSGustavo F. Padovan 20499a91a04aSGustavo F. Padovan l2cap_do_send(chan, skb); 20509a91a04aSGustavo F. Padovan err = len; 20519a91a04aSGustavo F. Padovan break; 20529a91a04aSGustavo F. Padovan 20539a91a04aSGustavo F. Padovan case L2CAP_MODE_ERTM: 20549a91a04aSGustavo F. Padovan case L2CAP_MODE_STREAMING: 20559a91a04aSGustavo F. Padovan /* Entire SDU fits into one PDU */ 20569a91a04aSGustavo F. Padovan if (len <= chan->remote_mps) { 20577e0ef6eeSAndrei Emeltchenko control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED); 20589a91a04aSGustavo F. Padovan skb = l2cap_create_iframe_pdu(chan, msg, len, control, 20599a91a04aSGustavo F. Padovan 0); 20609a91a04aSGustavo F. Padovan if (IS_ERR(skb)) 20619a91a04aSGustavo F. Padovan return PTR_ERR(skb); 20629a91a04aSGustavo F. Padovan 20639a91a04aSGustavo F. Padovan __skb_queue_tail(&chan->tx_q, skb); 20649a91a04aSGustavo F. Padovan 20659a91a04aSGustavo F. Padovan if (chan->tx_send_head == NULL) 20669a91a04aSGustavo F. Padovan chan->tx_send_head = skb; 20679a91a04aSGustavo F. Padovan 20689a91a04aSGustavo F. Padovan } else { 20699a91a04aSGustavo F. Padovan /* Segment SDU into multiples PDUs */ 20709a91a04aSGustavo F. Padovan err = l2cap_sar_segment_sdu(chan, msg, len); 20719a91a04aSGustavo F. Padovan if (err < 0) 20729a91a04aSGustavo F. Padovan return err; 20739a91a04aSGustavo F. Padovan } 20749a91a04aSGustavo F. Padovan 20759a91a04aSGustavo F. Padovan if (chan->mode == L2CAP_MODE_STREAMING) { 20769a91a04aSGustavo F. Padovan l2cap_streaming_send(chan); 20779a91a04aSGustavo F. Padovan err = len; 20789a91a04aSGustavo F. Padovan break; 20799a91a04aSGustavo F. Padovan } 20809a91a04aSGustavo F. Padovan 2081e2ab4353SGustavo F. Padovan if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) && 2082e2ab4353SGustavo F. Padovan test_bit(CONN_WAIT_F, &chan->conn_state)) { 20839a91a04aSGustavo F. Padovan err = len; 20849a91a04aSGustavo F. Padovan break; 20859a91a04aSGustavo F. Padovan } 20869a91a04aSGustavo F. Padovan 20879a91a04aSGustavo F. Padovan err = l2cap_ertm_send(chan); 20889a91a04aSGustavo F. Padovan if (err >= 0) 20899a91a04aSGustavo F. Padovan err = len; 20909a91a04aSGustavo F. Padovan 20919a91a04aSGustavo F. Padovan break; 20929a91a04aSGustavo F. Padovan 20939a91a04aSGustavo F. Padovan default: 20949a91a04aSGustavo F. Padovan BT_DBG("bad state %1.1x", chan->mode); 20959a91a04aSGustavo F. Padovan err = -EBADFD; 20969a91a04aSGustavo F. Padovan } 20979a91a04aSGustavo F. Padovan 20989a91a04aSGustavo F. Padovan return err; 20999a91a04aSGustavo F. Padovan } 21009a91a04aSGustavo F. Padovan 21010a708f8fSGustavo F. Padovan /* Copy frame to all raw sockets on that connection */ 21020a708f8fSGustavo F. Padovan static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) 21030a708f8fSGustavo F. Padovan { 21040a708f8fSGustavo F. Padovan struct sk_buff *nskb; 210548454079SGustavo F. Padovan struct l2cap_chan *chan; 21060a708f8fSGustavo F. Padovan 21070a708f8fSGustavo F. Padovan BT_DBG("conn %p", conn); 21080a708f8fSGustavo F. Padovan 21093df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 21103d57dc68SGustavo F. Padovan 21113df91ea2SAndrei Emeltchenko list_for_each_entry(chan, &conn->chan_l, list) { 211248454079SGustavo F. Padovan struct sock *sk = chan->sk; 2113715ec005SGustavo F. Padovan if (chan->chan_type != L2CAP_CHAN_RAW) 21140a708f8fSGustavo F. Padovan continue; 21150a708f8fSGustavo F. Padovan 21160a708f8fSGustavo F. Padovan /* Don't send frame to the socket it came from */ 21170a708f8fSGustavo F. Padovan if (skb->sk == sk) 21180a708f8fSGustavo F. Padovan continue; 21190a708f8fSGustavo F. Padovan nskb = skb_clone(skb, GFP_ATOMIC); 21200a708f8fSGustavo F. Padovan if (!nskb) 21210a708f8fSGustavo F. Padovan continue; 21220a708f8fSGustavo F. Padovan 212323070494SGustavo F. Padovan if (chan->ops->recv(chan->data, nskb)) 21240a708f8fSGustavo F. Padovan kfree_skb(nskb); 21250a708f8fSGustavo F. Padovan } 21263d57dc68SGustavo F. Padovan 21273df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 21280a708f8fSGustavo F. Padovan } 21290a708f8fSGustavo F. Padovan 21300a708f8fSGustavo F. Padovan /* ---- L2CAP signalling commands ---- */ 21310a708f8fSGustavo F. Padovan static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, 21320a708f8fSGustavo F. Padovan u8 code, u8 ident, u16 dlen, void *data) 21330a708f8fSGustavo F. Padovan { 21340a708f8fSGustavo F. Padovan struct sk_buff *skb, **frag; 21350a708f8fSGustavo F. Padovan struct l2cap_cmd_hdr *cmd; 21360a708f8fSGustavo F. Padovan struct l2cap_hdr *lh; 21370a708f8fSGustavo F. Padovan int len, count; 21380a708f8fSGustavo F. Padovan 21390a708f8fSGustavo F. Padovan BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", 21400a708f8fSGustavo F. Padovan conn, code, ident, dlen); 21410a708f8fSGustavo F. Padovan 21420a708f8fSGustavo F. Padovan len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; 21430a708f8fSGustavo F. Padovan count = min_t(unsigned int, conn->mtu, len); 21440a708f8fSGustavo F. Padovan 21450a708f8fSGustavo F. Padovan skb = bt_skb_alloc(count, GFP_ATOMIC); 21460a708f8fSGustavo F. Padovan if (!skb) 21470a708f8fSGustavo F. Padovan return NULL; 21480a708f8fSGustavo F. Padovan 21490a708f8fSGustavo F. Padovan lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); 21500a708f8fSGustavo F. Padovan lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); 21513300d9a9SClaudio Takahasi 21523300d9a9SClaudio Takahasi if (conn->hcon->type == LE_LINK) 21533300d9a9SClaudio Takahasi lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING); 21543300d9a9SClaudio Takahasi else 21550a708f8fSGustavo F. Padovan lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING); 21560a708f8fSGustavo F. Padovan 21570a708f8fSGustavo F. Padovan cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); 21580a708f8fSGustavo F. Padovan cmd->code = code; 21590a708f8fSGustavo F. Padovan cmd->ident = ident; 21600a708f8fSGustavo F. Padovan cmd->len = cpu_to_le16(dlen); 21610a708f8fSGustavo F. Padovan 21620a708f8fSGustavo F. Padovan if (dlen) { 21630a708f8fSGustavo F. Padovan count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE; 21640a708f8fSGustavo F. Padovan memcpy(skb_put(skb, count), data, count); 21650a708f8fSGustavo F. Padovan data += count; 21660a708f8fSGustavo F. Padovan } 21670a708f8fSGustavo F. Padovan 21680a708f8fSGustavo F. Padovan len -= skb->len; 21690a708f8fSGustavo F. Padovan 21700a708f8fSGustavo F. Padovan /* Continuation fragments (no L2CAP header) */ 21710a708f8fSGustavo F. Padovan frag = &skb_shinfo(skb)->frag_list; 21720a708f8fSGustavo F. Padovan while (len) { 21730a708f8fSGustavo F. Padovan count = min_t(unsigned int, conn->mtu, len); 21740a708f8fSGustavo F. Padovan 21750a708f8fSGustavo F. Padovan *frag = bt_skb_alloc(count, GFP_ATOMIC); 21760a708f8fSGustavo F. Padovan if (!*frag) 21770a708f8fSGustavo F. Padovan goto fail; 21780a708f8fSGustavo F. Padovan 21790a708f8fSGustavo F. Padovan memcpy(skb_put(*frag, count), data, count); 21800a708f8fSGustavo F. Padovan 21810a708f8fSGustavo F. Padovan len -= count; 21820a708f8fSGustavo F. Padovan data += count; 21830a708f8fSGustavo F. Padovan 21840a708f8fSGustavo F. Padovan frag = &(*frag)->next; 21850a708f8fSGustavo F. Padovan } 21860a708f8fSGustavo F. Padovan 21870a708f8fSGustavo F. Padovan return skb; 21880a708f8fSGustavo F. Padovan 21890a708f8fSGustavo F. Padovan fail: 21900a708f8fSGustavo F. Padovan kfree_skb(skb); 21910a708f8fSGustavo F. Padovan return NULL; 21920a708f8fSGustavo F. Padovan } 21930a708f8fSGustavo F. Padovan 21940a708f8fSGustavo F. Padovan static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val) 21950a708f8fSGustavo F. Padovan { 21960a708f8fSGustavo F. Padovan struct l2cap_conf_opt *opt = *ptr; 21970a708f8fSGustavo F. Padovan int len; 21980a708f8fSGustavo F. Padovan 21990a708f8fSGustavo F. Padovan len = L2CAP_CONF_OPT_SIZE + opt->len; 22000a708f8fSGustavo F. Padovan *ptr += len; 22010a708f8fSGustavo F. Padovan 22020a708f8fSGustavo F. Padovan *type = opt->type; 22030a708f8fSGustavo F. Padovan *olen = opt->len; 22040a708f8fSGustavo F. Padovan 22050a708f8fSGustavo F. Padovan switch (opt->len) { 22060a708f8fSGustavo F. Padovan case 1: 22070a708f8fSGustavo F. Padovan *val = *((u8 *) opt->val); 22080a708f8fSGustavo F. Padovan break; 22090a708f8fSGustavo F. Padovan 22100a708f8fSGustavo F. Padovan case 2: 22110a708f8fSGustavo F. Padovan *val = get_unaligned_le16(opt->val); 22120a708f8fSGustavo F. Padovan break; 22130a708f8fSGustavo F. Padovan 22140a708f8fSGustavo F. Padovan case 4: 22150a708f8fSGustavo F. Padovan *val = get_unaligned_le32(opt->val); 22160a708f8fSGustavo F. Padovan break; 22170a708f8fSGustavo F. Padovan 22180a708f8fSGustavo F. Padovan default: 22190a708f8fSGustavo F. Padovan *val = (unsigned long) opt->val; 22200a708f8fSGustavo F. Padovan break; 22210a708f8fSGustavo F. Padovan } 22220a708f8fSGustavo F. Padovan 22230a708f8fSGustavo F. Padovan BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val); 22240a708f8fSGustavo F. Padovan return len; 22250a708f8fSGustavo F. Padovan } 22260a708f8fSGustavo F. Padovan 22270a708f8fSGustavo F. Padovan static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) 22280a708f8fSGustavo F. Padovan { 22290a708f8fSGustavo F. Padovan struct l2cap_conf_opt *opt = *ptr; 22300a708f8fSGustavo F. Padovan 22310a708f8fSGustavo F. Padovan BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val); 22320a708f8fSGustavo F. Padovan 22330a708f8fSGustavo F. Padovan opt->type = type; 22340a708f8fSGustavo F. Padovan opt->len = len; 22350a708f8fSGustavo F. Padovan 22360a708f8fSGustavo F. Padovan switch (len) { 22370a708f8fSGustavo F. Padovan case 1: 22380a708f8fSGustavo F. Padovan *((u8 *) opt->val) = val; 22390a708f8fSGustavo F. Padovan break; 22400a708f8fSGustavo F. Padovan 22410a708f8fSGustavo F. Padovan case 2: 22420a708f8fSGustavo F. Padovan put_unaligned_le16(val, opt->val); 22430a708f8fSGustavo F. Padovan break; 22440a708f8fSGustavo F. Padovan 22450a708f8fSGustavo F. Padovan case 4: 22460a708f8fSGustavo F. Padovan put_unaligned_le32(val, opt->val); 22470a708f8fSGustavo F. Padovan break; 22480a708f8fSGustavo F. Padovan 22490a708f8fSGustavo F. Padovan default: 22500a708f8fSGustavo F. Padovan memcpy(opt->val, (void *) val, len); 22510a708f8fSGustavo F. Padovan break; 22520a708f8fSGustavo F. Padovan } 22530a708f8fSGustavo F. Padovan 22540a708f8fSGustavo F. Padovan *ptr += L2CAP_CONF_OPT_SIZE + len; 22550a708f8fSGustavo F. Padovan } 22560a708f8fSGustavo F. Padovan 2257f89cef09SAndrei Emeltchenko static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan) 2258f89cef09SAndrei Emeltchenko { 2259f89cef09SAndrei Emeltchenko struct l2cap_conf_efs efs; 2260f89cef09SAndrei Emeltchenko 2261f89cef09SAndrei Emeltchenko switch (chan->mode) { 2262f89cef09SAndrei Emeltchenko case L2CAP_MODE_ERTM: 2263f89cef09SAndrei Emeltchenko efs.id = chan->local_id; 2264f89cef09SAndrei Emeltchenko efs.stype = chan->local_stype; 2265f89cef09SAndrei Emeltchenko efs.msdu = cpu_to_le16(chan->local_msdu); 2266f89cef09SAndrei Emeltchenko efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime); 2267f89cef09SAndrei Emeltchenko efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT); 2268f89cef09SAndrei Emeltchenko efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO); 2269f89cef09SAndrei Emeltchenko break; 2270f89cef09SAndrei Emeltchenko 2271f89cef09SAndrei Emeltchenko case L2CAP_MODE_STREAMING: 2272f89cef09SAndrei Emeltchenko efs.id = 1; 2273f89cef09SAndrei Emeltchenko efs.stype = L2CAP_SERV_BESTEFFORT; 2274f89cef09SAndrei Emeltchenko efs.msdu = cpu_to_le16(chan->local_msdu); 2275f89cef09SAndrei Emeltchenko efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime); 2276f89cef09SAndrei Emeltchenko efs.acc_lat = 0; 2277f89cef09SAndrei Emeltchenko efs.flush_to = 0; 2278f89cef09SAndrei Emeltchenko break; 2279f89cef09SAndrei Emeltchenko 2280f89cef09SAndrei Emeltchenko default: 2281f89cef09SAndrei Emeltchenko return; 2282f89cef09SAndrei Emeltchenko } 2283f89cef09SAndrei Emeltchenko 2284f89cef09SAndrei Emeltchenko l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs), 2285f89cef09SAndrei Emeltchenko (unsigned long) &efs); 2286f89cef09SAndrei Emeltchenko } 2287f89cef09SAndrei Emeltchenko 2288721c4181SGustavo F. Padovan static void l2cap_ack_timeout(struct work_struct *work) 22890a708f8fSGustavo F. Padovan { 2290721c4181SGustavo F. Padovan struct l2cap_chan *chan = container_of(work, struct l2cap_chan, 2291721c4181SGustavo F. Padovan ack_timer.work); 22920a708f8fSGustavo F. Padovan 22932fb9b3d4SGustavo F. Padovan BT_DBG("chan %p", chan); 22942fb9b3d4SGustavo F. Padovan 22956be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 22966be36555SAndrei Emeltchenko 2297b17e73bbSSzymon Janc __l2cap_send_ack(chan); 22986be36555SAndrei Emeltchenko 22996be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 230009bfb2eeSSzymon Janc 230109bfb2eeSSzymon Janc l2cap_chan_put(chan); 23020a708f8fSGustavo F. Padovan } 23030a708f8fSGustavo F. Padovan 23043c588192SMat Martineau static inline int l2cap_ertm_init(struct l2cap_chan *chan) 23050a708f8fSGustavo F. Padovan { 23063c588192SMat Martineau int err; 23073c588192SMat Martineau 2308105bdf9eSMat Martineau chan->next_tx_seq = 0; 2309105bdf9eSMat Martineau chan->expected_tx_seq = 0; 231042e5c802SGustavo F. Padovan chan->expected_ack_seq = 0; 23116a026610SGustavo F. Padovan chan->unacked_frames = 0; 231242e5c802SGustavo F. Padovan chan->buffer_seq = 0; 23136a026610SGustavo F. Padovan chan->num_acked = 0; 23146a026610SGustavo F. Padovan chan->frames_sent = 0; 2315105bdf9eSMat Martineau chan->last_acked_seq = 0; 2316105bdf9eSMat Martineau chan->sdu = NULL; 2317105bdf9eSMat Martineau chan->sdu_last_frag = NULL; 2318105bdf9eSMat Martineau chan->sdu_len = 0; 2319105bdf9eSMat Martineau 2320105bdf9eSMat Martineau if (chan->mode != L2CAP_MODE_ERTM) 2321105bdf9eSMat Martineau return 0; 2322105bdf9eSMat Martineau 2323105bdf9eSMat Martineau chan->rx_state = L2CAP_RX_STATE_RECV; 2324105bdf9eSMat Martineau chan->tx_state = L2CAP_TX_STATE_XMIT; 23250a708f8fSGustavo F. Padovan 2326721c4181SGustavo F. Padovan INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout); 2327721c4181SGustavo F. Padovan INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout); 2328721c4181SGustavo F. Padovan INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout); 23290a708f8fSGustavo F. Padovan 2330f1c6775bSGustavo F. Padovan skb_queue_head_init(&chan->srej_q); 2331105bdf9eSMat Martineau skb_queue_head_init(&chan->tx_q); 23320a708f8fSGustavo F. Padovan 233339d5a3eeSGustavo F. Padovan INIT_LIST_HEAD(&chan->srej_l); 23343c588192SMat Martineau err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win); 23353c588192SMat Martineau if (err < 0) 23363c588192SMat Martineau return err; 23373c588192SMat Martineau 23383c588192SMat Martineau return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win); 23390a708f8fSGustavo F. Padovan } 23400a708f8fSGustavo F. Padovan 23410a708f8fSGustavo F. Padovan static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) 23420a708f8fSGustavo F. Padovan { 23430a708f8fSGustavo F. Padovan switch (mode) { 23440a708f8fSGustavo F. Padovan case L2CAP_MODE_STREAMING: 23450a708f8fSGustavo F. Padovan case L2CAP_MODE_ERTM: 23460a708f8fSGustavo F. Padovan if (l2cap_mode_supported(mode, remote_feat_mask)) 23470a708f8fSGustavo F. Padovan return mode; 23480a708f8fSGustavo F. Padovan /* fall through */ 23490a708f8fSGustavo F. Padovan default: 23500a708f8fSGustavo F. Padovan return L2CAP_MODE_BASIC; 23510a708f8fSGustavo F. Padovan } 23520a708f8fSGustavo F. Padovan } 23530a708f8fSGustavo F. Padovan 23546327eb98SAndrei Emeltchenko static inline bool __l2cap_ews_supported(struct l2cap_chan *chan) 23556327eb98SAndrei Emeltchenko { 23566327eb98SAndrei Emeltchenko return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW; 23576327eb98SAndrei Emeltchenko } 23586327eb98SAndrei Emeltchenko 2359f89cef09SAndrei Emeltchenko static inline bool __l2cap_efs_supported(struct l2cap_chan *chan) 2360f89cef09SAndrei Emeltchenko { 2361f89cef09SAndrei Emeltchenko return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW; 2362f89cef09SAndrei Emeltchenko } 2363f89cef09SAndrei Emeltchenko 23646327eb98SAndrei Emeltchenko static inline void l2cap_txwin_setup(struct l2cap_chan *chan) 23656327eb98SAndrei Emeltchenko { 23666327eb98SAndrei Emeltchenko if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW && 2367836be934SAndrei Emeltchenko __l2cap_ews_supported(chan)) { 23686327eb98SAndrei Emeltchenko /* use extended control field */ 23696327eb98SAndrei Emeltchenko set_bit(FLAG_EXT_CTRL, &chan->flags); 2370836be934SAndrei Emeltchenko chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW; 2371836be934SAndrei Emeltchenko } else { 23726327eb98SAndrei Emeltchenko chan->tx_win = min_t(u16, chan->tx_win, 23736327eb98SAndrei Emeltchenko L2CAP_DEFAULT_TX_WINDOW); 2374836be934SAndrei Emeltchenko chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; 2375836be934SAndrei Emeltchenko } 23766327eb98SAndrei Emeltchenko } 23776327eb98SAndrei Emeltchenko 2378710f9b0aSGustavo F. Padovan static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) 23790a708f8fSGustavo F. Padovan { 23800a708f8fSGustavo F. Padovan struct l2cap_conf_req *req = data; 23810c1bc5c6SGustavo F. Padovan struct l2cap_conf_rfc rfc = { .mode = chan->mode }; 23820a708f8fSGustavo F. Padovan void *ptr = req->data; 2383c8f79162SAndrei Emeltchenko u16 size; 23840a708f8fSGustavo F. Padovan 238549208c9cSGustavo F. Padovan BT_DBG("chan %p", chan); 23860a708f8fSGustavo F. Padovan 238773ffa904SGustavo F. Padovan if (chan->num_conf_req || chan->num_conf_rsp) 23880a708f8fSGustavo F. Padovan goto done; 23890a708f8fSGustavo F. Padovan 23900c1bc5c6SGustavo F. Padovan switch (chan->mode) { 23910a708f8fSGustavo F. Padovan case L2CAP_MODE_STREAMING: 23920a708f8fSGustavo F. Padovan case L2CAP_MODE_ERTM: 2393c1360a1cSGustavo F. Padovan if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) 23940a708f8fSGustavo F. Padovan break; 23950a708f8fSGustavo F. Padovan 2396f89cef09SAndrei Emeltchenko if (__l2cap_efs_supported(chan)) 2397f89cef09SAndrei Emeltchenko set_bit(FLAG_EFS_ENABLE, &chan->flags); 2398f89cef09SAndrei Emeltchenko 23990a708f8fSGustavo F. Padovan /* fall through */ 24000a708f8fSGustavo F. Padovan default: 24018c1d787bSGustavo F. Padovan chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask); 24020a708f8fSGustavo F. Padovan break; 24030a708f8fSGustavo F. Padovan } 24040a708f8fSGustavo F. Padovan 24050a708f8fSGustavo F. Padovan done: 24060c1bc5c6SGustavo F. Padovan if (chan->imtu != L2CAP_DEFAULT_MTU) 24070c1bc5c6SGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); 24080a708f8fSGustavo F. Padovan 24090c1bc5c6SGustavo F. Padovan switch (chan->mode) { 24100a708f8fSGustavo F. Padovan case L2CAP_MODE_BASIC: 24118c1d787bSGustavo F. Padovan if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) && 24128c1d787bSGustavo F. Padovan !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING)) 24130a708f8fSGustavo F. Padovan break; 24140a708f8fSGustavo F. Padovan 24150a708f8fSGustavo F. Padovan rfc.mode = L2CAP_MODE_BASIC; 24160a708f8fSGustavo F. Padovan rfc.txwin_size = 0; 24170a708f8fSGustavo F. Padovan rfc.max_transmit = 0; 24180a708f8fSGustavo F. Padovan rfc.retrans_timeout = 0; 24190a708f8fSGustavo F. Padovan rfc.monitor_timeout = 0; 24200a708f8fSGustavo F. Padovan rfc.max_pdu_size = 0; 24210a708f8fSGustavo F. Padovan 24220a708f8fSGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), 24230a708f8fSGustavo F. Padovan (unsigned long) &rfc); 24240a708f8fSGustavo F. Padovan break; 24250a708f8fSGustavo F. Padovan 24260a708f8fSGustavo F. Padovan case L2CAP_MODE_ERTM: 24270a708f8fSGustavo F. Padovan rfc.mode = L2CAP_MODE_ERTM; 242847d1ec61SGustavo F. Padovan rfc.max_transmit = chan->max_tx; 24290a708f8fSGustavo F. Padovan rfc.retrans_timeout = 0; 24300a708f8fSGustavo F. Padovan rfc.monitor_timeout = 0; 2431c8f79162SAndrei Emeltchenko 2432c8f79162SAndrei Emeltchenko size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu - 2433c8f79162SAndrei Emeltchenko L2CAP_EXT_HDR_SIZE - 2434c8f79162SAndrei Emeltchenko L2CAP_SDULEN_SIZE - 2435c8f79162SAndrei Emeltchenko L2CAP_FCS_SIZE); 2436c8f79162SAndrei Emeltchenko rfc.max_pdu_size = cpu_to_le16(size); 24370a708f8fSGustavo F. Padovan 24386327eb98SAndrei Emeltchenko l2cap_txwin_setup(chan); 24396327eb98SAndrei Emeltchenko 24406327eb98SAndrei Emeltchenko rfc.txwin_size = min_t(u16, chan->tx_win, 24416327eb98SAndrei Emeltchenko L2CAP_DEFAULT_TX_WINDOW); 24420a708f8fSGustavo F. Padovan 24430a708f8fSGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), 24440a708f8fSGustavo F. Padovan (unsigned long) &rfc); 24450a708f8fSGustavo F. Padovan 2446f89cef09SAndrei Emeltchenko if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) 2447f89cef09SAndrei Emeltchenko l2cap_add_opt_efs(&ptr, chan); 2448f89cef09SAndrei Emeltchenko 24498c1d787bSGustavo F. Padovan if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) 24500a708f8fSGustavo F. Padovan break; 24510a708f8fSGustavo F. Padovan 245247d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_NONE || 2453c1360a1cSGustavo F. Padovan test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { 245447d1ec61SGustavo F. Padovan chan->fcs = L2CAP_FCS_NONE; 245547d1ec61SGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); 24560a708f8fSGustavo F. Padovan } 24576327eb98SAndrei Emeltchenko 24586327eb98SAndrei Emeltchenko if (test_bit(FLAG_EXT_CTRL, &chan->flags)) 24596327eb98SAndrei Emeltchenko l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, 24606327eb98SAndrei Emeltchenko chan->tx_win); 24610a708f8fSGustavo F. Padovan break; 24620a708f8fSGustavo F. Padovan 24630a708f8fSGustavo F. Padovan case L2CAP_MODE_STREAMING: 24640a708f8fSGustavo F. Padovan rfc.mode = L2CAP_MODE_STREAMING; 24650a708f8fSGustavo F. Padovan rfc.txwin_size = 0; 24660a708f8fSGustavo F. Padovan rfc.max_transmit = 0; 24670a708f8fSGustavo F. Padovan rfc.retrans_timeout = 0; 24680a708f8fSGustavo F. Padovan rfc.monitor_timeout = 0; 2469c8f79162SAndrei Emeltchenko 2470c8f79162SAndrei Emeltchenko size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu - 2471c8f79162SAndrei Emeltchenko L2CAP_EXT_HDR_SIZE - 2472c8f79162SAndrei Emeltchenko L2CAP_SDULEN_SIZE - 2473c8f79162SAndrei Emeltchenko L2CAP_FCS_SIZE); 2474c8f79162SAndrei Emeltchenko rfc.max_pdu_size = cpu_to_le16(size); 24750a708f8fSGustavo F. Padovan 24760a708f8fSGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), 24770a708f8fSGustavo F. Padovan (unsigned long) &rfc); 24780a708f8fSGustavo F. Padovan 2479f89cef09SAndrei Emeltchenko if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) 2480f89cef09SAndrei Emeltchenko l2cap_add_opt_efs(&ptr, chan); 2481f89cef09SAndrei Emeltchenko 24828c1d787bSGustavo F. Padovan if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) 24830a708f8fSGustavo F. Padovan break; 24840a708f8fSGustavo F. Padovan 248547d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_NONE || 2486c1360a1cSGustavo F. Padovan test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) { 248747d1ec61SGustavo F. Padovan chan->fcs = L2CAP_FCS_NONE; 248847d1ec61SGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); 24890a708f8fSGustavo F. Padovan } 24900a708f8fSGustavo F. Padovan break; 24910a708f8fSGustavo F. Padovan } 24920a708f8fSGustavo F. Padovan 2493fe4128e0SGustavo F. Padovan req->dcid = cpu_to_le16(chan->dcid); 24940a708f8fSGustavo F. Padovan req->flags = cpu_to_le16(0); 24950a708f8fSGustavo F. Padovan 24960a708f8fSGustavo F. Padovan return ptr - data; 24970a708f8fSGustavo F. Padovan } 24980a708f8fSGustavo F. Padovan 249973ffa904SGustavo F. Padovan static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) 25000a708f8fSGustavo F. Padovan { 25010a708f8fSGustavo F. Padovan struct l2cap_conf_rsp *rsp = data; 25020a708f8fSGustavo F. Padovan void *ptr = rsp->data; 250373ffa904SGustavo F. Padovan void *req = chan->conf_req; 250473ffa904SGustavo F. Padovan int len = chan->conf_len; 25050a708f8fSGustavo F. Padovan int type, hint, olen; 25060a708f8fSGustavo F. Padovan unsigned long val; 25070a708f8fSGustavo F. Padovan struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; 250842dceae2SAndrei Emeltchenko struct l2cap_conf_efs efs; 250942dceae2SAndrei Emeltchenko u8 remote_efs = 0; 25100a708f8fSGustavo F. Padovan u16 mtu = L2CAP_DEFAULT_MTU; 25110a708f8fSGustavo F. Padovan u16 result = L2CAP_CONF_SUCCESS; 2512c8f79162SAndrei Emeltchenko u16 size; 25130a708f8fSGustavo F. Padovan 251473ffa904SGustavo F. Padovan BT_DBG("chan %p", chan); 25150a708f8fSGustavo F. Padovan 25160a708f8fSGustavo F. Padovan while (len >= L2CAP_CONF_OPT_SIZE) { 25170a708f8fSGustavo F. Padovan len -= l2cap_get_conf_opt(&req, &type, &olen, &val); 25180a708f8fSGustavo F. Padovan 25190a708f8fSGustavo F. Padovan hint = type & L2CAP_CONF_HINT; 25200a708f8fSGustavo F. Padovan type &= L2CAP_CONF_MASK; 25210a708f8fSGustavo F. Padovan 25220a708f8fSGustavo F. Padovan switch (type) { 25230a708f8fSGustavo F. Padovan case L2CAP_CONF_MTU: 25240a708f8fSGustavo F. Padovan mtu = val; 25250a708f8fSGustavo F. Padovan break; 25260a708f8fSGustavo F. Padovan 25270a708f8fSGustavo F. Padovan case L2CAP_CONF_FLUSH_TO: 25280c1bc5c6SGustavo F. Padovan chan->flush_to = val; 25290a708f8fSGustavo F. Padovan break; 25300a708f8fSGustavo F. Padovan 25310a708f8fSGustavo F. Padovan case L2CAP_CONF_QOS: 25320a708f8fSGustavo F. Padovan break; 25330a708f8fSGustavo F. Padovan 25340a708f8fSGustavo F. Padovan case L2CAP_CONF_RFC: 25350a708f8fSGustavo F. Padovan if (olen == sizeof(rfc)) 25360a708f8fSGustavo F. Padovan memcpy(&rfc, (void *) val, olen); 25370a708f8fSGustavo F. Padovan break; 25380a708f8fSGustavo F. Padovan 25390a708f8fSGustavo F. Padovan case L2CAP_CONF_FCS: 25400a708f8fSGustavo F. Padovan if (val == L2CAP_FCS_NONE) 2541c1360a1cSGustavo F. Padovan set_bit(CONF_NO_FCS_RECV, &chan->conf_state); 254242dceae2SAndrei Emeltchenko break; 25430a708f8fSGustavo F. Padovan 254442dceae2SAndrei Emeltchenko case L2CAP_CONF_EFS: 254542dceae2SAndrei Emeltchenko remote_efs = 1; 254642dceae2SAndrei Emeltchenko if (olen == sizeof(efs)) 254742dceae2SAndrei Emeltchenko memcpy(&efs, (void *) val, olen); 25480a708f8fSGustavo F. Padovan break; 25490a708f8fSGustavo F. Padovan 25506327eb98SAndrei Emeltchenko case L2CAP_CONF_EWS: 25516327eb98SAndrei Emeltchenko if (!enable_hs) 25526327eb98SAndrei Emeltchenko return -ECONNREFUSED; 25536327eb98SAndrei Emeltchenko 25546327eb98SAndrei Emeltchenko set_bit(FLAG_EXT_CTRL, &chan->flags); 25556327eb98SAndrei Emeltchenko set_bit(CONF_EWS_RECV, &chan->conf_state); 2556836be934SAndrei Emeltchenko chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW; 25576327eb98SAndrei Emeltchenko chan->remote_tx_win = val; 25580a708f8fSGustavo F. Padovan break; 25590a708f8fSGustavo F. Padovan 25600a708f8fSGustavo F. Padovan default: 25610a708f8fSGustavo F. Padovan if (hint) 25620a708f8fSGustavo F. Padovan break; 25630a708f8fSGustavo F. Padovan 25640a708f8fSGustavo F. Padovan result = L2CAP_CONF_UNKNOWN; 25650a708f8fSGustavo F. Padovan *((u8 *) ptr++) = type; 25660a708f8fSGustavo F. Padovan break; 25670a708f8fSGustavo F. Padovan } 25680a708f8fSGustavo F. Padovan } 25690a708f8fSGustavo F. Padovan 257073ffa904SGustavo F. Padovan if (chan->num_conf_rsp || chan->num_conf_req > 1) 25710a708f8fSGustavo F. Padovan goto done; 25720a708f8fSGustavo F. Padovan 25730c1bc5c6SGustavo F. Padovan switch (chan->mode) { 25740a708f8fSGustavo F. Padovan case L2CAP_MODE_STREAMING: 25750a708f8fSGustavo F. Padovan case L2CAP_MODE_ERTM: 2576c1360a1cSGustavo F. Padovan if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) { 25770c1bc5c6SGustavo F. Padovan chan->mode = l2cap_select_mode(rfc.mode, 25788c1d787bSGustavo F. Padovan chan->conn->feat_mask); 25790a708f8fSGustavo F. Padovan break; 25800a708f8fSGustavo F. Padovan } 25810a708f8fSGustavo F. Padovan 258242dceae2SAndrei Emeltchenko if (remote_efs) { 258342dceae2SAndrei Emeltchenko if (__l2cap_efs_supported(chan)) 258442dceae2SAndrei Emeltchenko set_bit(FLAG_EFS_ENABLE, &chan->flags); 258542dceae2SAndrei Emeltchenko else 258642dceae2SAndrei Emeltchenko return -ECONNREFUSED; 258742dceae2SAndrei Emeltchenko } 258842dceae2SAndrei Emeltchenko 25890c1bc5c6SGustavo F. Padovan if (chan->mode != rfc.mode) 25900a708f8fSGustavo F. Padovan return -ECONNREFUSED; 25910a708f8fSGustavo F. Padovan 25920a708f8fSGustavo F. Padovan break; 25930a708f8fSGustavo F. Padovan } 25940a708f8fSGustavo F. Padovan 25950a708f8fSGustavo F. Padovan done: 25960c1bc5c6SGustavo F. Padovan if (chan->mode != rfc.mode) { 25970a708f8fSGustavo F. Padovan result = L2CAP_CONF_UNACCEPT; 25980c1bc5c6SGustavo F. Padovan rfc.mode = chan->mode; 25990a708f8fSGustavo F. Padovan 260073ffa904SGustavo F. Padovan if (chan->num_conf_rsp == 1) 26010a708f8fSGustavo F. Padovan return -ECONNREFUSED; 26020a708f8fSGustavo F. Padovan 26030a708f8fSGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, 26040a708f8fSGustavo F. Padovan sizeof(rfc), (unsigned long) &rfc); 26050a708f8fSGustavo F. Padovan } 26060a708f8fSGustavo F. Padovan 26070a708f8fSGustavo F. Padovan if (result == L2CAP_CONF_SUCCESS) { 26080a708f8fSGustavo F. Padovan /* Configure output options and let the other side know 26090a708f8fSGustavo F. Padovan * which ones we don't like. */ 26100a708f8fSGustavo F. Padovan 26110a708f8fSGustavo F. Padovan if (mtu < L2CAP_DEFAULT_MIN_MTU) 26120a708f8fSGustavo F. Padovan result = L2CAP_CONF_UNACCEPT; 26130a708f8fSGustavo F. Padovan else { 26140c1bc5c6SGustavo F. Padovan chan->omtu = mtu; 2615c1360a1cSGustavo F. Padovan set_bit(CONF_MTU_DONE, &chan->conf_state); 26160a708f8fSGustavo F. Padovan } 26170c1bc5c6SGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu); 26180a708f8fSGustavo F. Padovan 261942dceae2SAndrei Emeltchenko if (remote_efs) { 262042dceae2SAndrei Emeltchenko if (chan->local_stype != L2CAP_SERV_NOTRAFIC && 262142dceae2SAndrei Emeltchenko efs.stype != L2CAP_SERV_NOTRAFIC && 262242dceae2SAndrei Emeltchenko efs.stype != chan->local_stype) { 262342dceae2SAndrei Emeltchenko 262442dceae2SAndrei Emeltchenko result = L2CAP_CONF_UNACCEPT; 262542dceae2SAndrei Emeltchenko 262642dceae2SAndrei Emeltchenko if (chan->num_conf_req >= 1) 262742dceae2SAndrei Emeltchenko return -ECONNREFUSED; 262842dceae2SAndrei Emeltchenko 262942dceae2SAndrei Emeltchenko l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, 263042dceae2SAndrei Emeltchenko sizeof(efs), 263142dceae2SAndrei Emeltchenko (unsigned long) &efs); 26320e8b207eSAndrei Emeltchenko } else { 26333e6b3b95SGustavo F. Padovan /* Send PENDING Conf Rsp */ 26340e8b207eSAndrei Emeltchenko result = L2CAP_CONF_PENDING; 26350e8b207eSAndrei Emeltchenko set_bit(CONF_LOC_CONF_PEND, &chan->conf_state); 263642dceae2SAndrei Emeltchenko } 263742dceae2SAndrei Emeltchenko } 263842dceae2SAndrei Emeltchenko 26390a708f8fSGustavo F. Padovan switch (rfc.mode) { 26400a708f8fSGustavo F. Padovan case L2CAP_MODE_BASIC: 264147d1ec61SGustavo F. Padovan chan->fcs = L2CAP_FCS_NONE; 2642c1360a1cSGustavo F. Padovan set_bit(CONF_MODE_DONE, &chan->conf_state); 26430a708f8fSGustavo F. Padovan break; 26440a708f8fSGustavo F. Padovan 26450a708f8fSGustavo F. Padovan case L2CAP_MODE_ERTM: 26466327eb98SAndrei Emeltchenko if (!test_bit(CONF_EWS_RECV, &chan->conf_state)) 26472c03a7a4SGustavo F. Padovan chan->remote_tx_win = rfc.txwin_size; 26486327eb98SAndrei Emeltchenko else 26496327eb98SAndrei Emeltchenko rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW; 26506327eb98SAndrei Emeltchenko 26512c03a7a4SGustavo F. Padovan chan->remote_max_tx = rfc.max_transmit; 26520a708f8fSGustavo F. Padovan 2653c8f79162SAndrei Emeltchenko size = min_t(u16, le16_to_cpu(rfc.max_pdu_size), 2654c8f79162SAndrei Emeltchenko chan->conn->mtu - 2655c8f79162SAndrei Emeltchenko L2CAP_EXT_HDR_SIZE - 2656c8f79162SAndrei Emeltchenko L2CAP_SDULEN_SIZE - 2657c8f79162SAndrei Emeltchenko L2CAP_FCS_SIZE); 2658c8f79162SAndrei Emeltchenko rfc.max_pdu_size = cpu_to_le16(size); 2659c8f79162SAndrei Emeltchenko chan->remote_mps = size; 26600a708f8fSGustavo F. Padovan 26610a708f8fSGustavo F. Padovan rfc.retrans_timeout = 26624fd21a88SAndrei Emeltchenko __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); 26630a708f8fSGustavo F. Padovan rfc.monitor_timeout = 26644fd21a88SAndrei Emeltchenko __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); 26650a708f8fSGustavo F. Padovan 2666c1360a1cSGustavo F. Padovan set_bit(CONF_MODE_DONE, &chan->conf_state); 26670a708f8fSGustavo F. Padovan 26680a708f8fSGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, 26690a708f8fSGustavo F. Padovan sizeof(rfc), (unsigned long) &rfc); 26700a708f8fSGustavo F. Padovan 267142dceae2SAndrei Emeltchenko if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) { 267242dceae2SAndrei Emeltchenko chan->remote_id = efs.id; 267342dceae2SAndrei Emeltchenko chan->remote_stype = efs.stype; 267442dceae2SAndrei Emeltchenko chan->remote_msdu = le16_to_cpu(efs.msdu); 267542dceae2SAndrei Emeltchenko chan->remote_flush_to = 267642dceae2SAndrei Emeltchenko le32_to_cpu(efs.flush_to); 267742dceae2SAndrei Emeltchenko chan->remote_acc_lat = 267842dceae2SAndrei Emeltchenko le32_to_cpu(efs.acc_lat); 267942dceae2SAndrei Emeltchenko chan->remote_sdu_itime = 268042dceae2SAndrei Emeltchenko le32_to_cpu(efs.sdu_itime); 268142dceae2SAndrei Emeltchenko l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, 268242dceae2SAndrei Emeltchenko sizeof(efs), (unsigned long) &efs); 268342dceae2SAndrei Emeltchenko } 26840a708f8fSGustavo F. Padovan break; 26850a708f8fSGustavo F. Padovan 26860a708f8fSGustavo F. Padovan case L2CAP_MODE_STREAMING: 2687c8f79162SAndrei Emeltchenko size = min_t(u16, le16_to_cpu(rfc.max_pdu_size), 2688c8f79162SAndrei Emeltchenko chan->conn->mtu - 2689c8f79162SAndrei Emeltchenko L2CAP_EXT_HDR_SIZE - 2690c8f79162SAndrei Emeltchenko L2CAP_SDULEN_SIZE - 2691c8f79162SAndrei Emeltchenko L2CAP_FCS_SIZE); 2692c8f79162SAndrei Emeltchenko rfc.max_pdu_size = cpu_to_le16(size); 2693c8f79162SAndrei Emeltchenko chan->remote_mps = size; 26940a708f8fSGustavo F. Padovan 2695c1360a1cSGustavo F. Padovan set_bit(CONF_MODE_DONE, &chan->conf_state); 26960a708f8fSGustavo F. Padovan 26970a708f8fSGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, 26980a708f8fSGustavo F. Padovan sizeof(rfc), (unsigned long) &rfc); 26990a708f8fSGustavo F. Padovan 27000a708f8fSGustavo F. Padovan break; 27010a708f8fSGustavo F. Padovan 27020a708f8fSGustavo F. Padovan default: 27030a708f8fSGustavo F. Padovan result = L2CAP_CONF_UNACCEPT; 27040a708f8fSGustavo F. Padovan 27050a708f8fSGustavo F. Padovan memset(&rfc, 0, sizeof(rfc)); 27060c1bc5c6SGustavo F. Padovan rfc.mode = chan->mode; 27070a708f8fSGustavo F. Padovan } 27080a708f8fSGustavo F. Padovan 27090a708f8fSGustavo F. Padovan if (result == L2CAP_CONF_SUCCESS) 2710c1360a1cSGustavo F. Padovan set_bit(CONF_OUTPUT_DONE, &chan->conf_state); 27110a708f8fSGustavo F. Padovan } 2712fe4128e0SGustavo F. Padovan rsp->scid = cpu_to_le16(chan->dcid); 27130a708f8fSGustavo F. Padovan rsp->result = cpu_to_le16(result); 27140a708f8fSGustavo F. Padovan rsp->flags = cpu_to_le16(0x0000); 27150a708f8fSGustavo F. Padovan 27160a708f8fSGustavo F. Padovan return ptr - data; 27170a708f8fSGustavo F. Padovan } 27180a708f8fSGustavo F. Padovan 2719b4450035SGustavo F. Padovan static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result) 27200a708f8fSGustavo F. Padovan { 27210a708f8fSGustavo F. Padovan struct l2cap_conf_req *req = data; 27220a708f8fSGustavo F. Padovan void *ptr = req->data; 27230a708f8fSGustavo F. Padovan int type, olen; 27240a708f8fSGustavo F. Padovan unsigned long val; 272536e999a8SMat Martineau struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; 272666af7aafSAndrei Emeltchenko struct l2cap_conf_efs efs; 27270a708f8fSGustavo F. Padovan 2728fe4128e0SGustavo F. Padovan BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data); 27290a708f8fSGustavo F. Padovan 27300a708f8fSGustavo F. Padovan while (len >= L2CAP_CONF_OPT_SIZE) { 27310a708f8fSGustavo F. Padovan len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); 27320a708f8fSGustavo F. Padovan 27330a708f8fSGustavo F. Padovan switch (type) { 27340a708f8fSGustavo F. Padovan case L2CAP_CONF_MTU: 27350a708f8fSGustavo F. Padovan if (val < L2CAP_DEFAULT_MIN_MTU) { 27360a708f8fSGustavo F. Padovan *result = L2CAP_CONF_UNACCEPT; 27370c1bc5c6SGustavo F. Padovan chan->imtu = L2CAP_DEFAULT_MIN_MTU; 27380a708f8fSGustavo F. Padovan } else 27390c1bc5c6SGustavo F. Padovan chan->imtu = val; 27400c1bc5c6SGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); 27410a708f8fSGustavo F. Padovan break; 27420a708f8fSGustavo F. Padovan 27430a708f8fSGustavo F. Padovan case L2CAP_CONF_FLUSH_TO: 27440c1bc5c6SGustavo F. Padovan chan->flush_to = val; 27450a708f8fSGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 27460c1bc5c6SGustavo F. Padovan 2, chan->flush_to); 27470a708f8fSGustavo F. Padovan break; 27480a708f8fSGustavo F. Padovan 27490a708f8fSGustavo F. Padovan case L2CAP_CONF_RFC: 27500a708f8fSGustavo F. Padovan if (olen == sizeof(rfc)) 27510a708f8fSGustavo F. Padovan memcpy(&rfc, (void *)val, olen); 27520a708f8fSGustavo F. Padovan 2753c1360a1cSGustavo F. Padovan if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) && 27540c1bc5c6SGustavo F. Padovan rfc.mode != chan->mode) 27550a708f8fSGustavo F. Padovan return -ECONNREFUSED; 27560a708f8fSGustavo F. Padovan 275747d1ec61SGustavo F. Padovan chan->fcs = 0; 27580a708f8fSGustavo F. Padovan 27590a708f8fSGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, 27600a708f8fSGustavo F. Padovan sizeof(rfc), (unsigned long) &rfc); 27610a708f8fSGustavo F. Padovan break; 27626327eb98SAndrei Emeltchenko 27636327eb98SAndrei Emeltchenko case L2CAP_CONF_EWS: 27646327eb98SAndrei Emeltchenko chan->tx_win = min_t(u16, val, 27656327eb98SAndrei Emeltchenko L2CAP_DEFAULT_EXT_WINDOW); 27663e6b3b95SGustavo F. Padovan l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, 27673e6b3b95SGustavo F. Padovan chan->tx_win); 27686327eb98SAndrei Emeltchenko break; 276966af7aafSAndrei Emeltchenko 277066af7aafSAndrei Emeltchenko case L2CAP_CONF_EFS: 277166af7aafSAndrei Emeltchenko if (olen == sizeof(efs)) 277266af7aafSAndrei Emeltchenko memcpy(&efs, (void *)val, olen); 277366af7aafSAndrei Emeltchenko 277466af7aafSAndrei Emeltchenko if (chan->local_stype != L2CAP_SERV_NOTRAFIC && 277566af7aafSAndrei Emeltchenko efs.stype != L2CAP_SERV_NOTRAFIC && 277666af7aafSAndrei Emeltchenko efs.stype != chan->local_stype) 277766af7aafSAndrei Emeltchenko return -ECONNREFUSED; 277866af7aafSAndrei Emeltchenko 277966af7aafSAndrei Emeltchenko l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, 278066af7aafSAndrei Emeltchenko sizeof(efs), (unsigned long) &efs); 278166af7aafSAndrei Emeltchenko break; 27820a708f8fSGustavo F. Padovan } 27830a708f8fSGustavo F. Padovan } 27840a708f8fSGustavo F. Padovan 27850c1bc5c6SGustavo F. Padovan if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode) 27860a708f8fSGustavo F. Padovan return -ECONNREFUSED; 27870a708f8fSGustavo F. Padovan 27880c1bc5c6SGustavo F. Padovan chan->mode = rfc.mode; 27890a708f8fSGustavo F. Padovan 27900e8b207eSAndrei Emeltchenko if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) { 27910a708f8fSGustavo F. Padovan switch (rfc.mode) { 27920a708f8fSGustavo F. Padovan case L2CAP_MODE_ERTM: 279347d1ec61SGustavo F. Padovan chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); 279447d1ec61SGustavo F. Padovan chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); 279547d1ec61SGustavo F. Padovan chan->mps = le16_to_cpu(rfc.max_pdu_size); 279666af7aafSAndrei Emeltchenko 279766af7aafSAndrei Emeltchenko if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) { 279866af7aafSAndrei Emeltchenko chan->local_msdu = le16_to_cpu(efs.msdu); 279966af7aafSAndrei Emeltchenko chan->local_sdu_itime = 280066af7aafSAndrei Emeltchenko le32_to_cpu(efs.sdu_itime); 280166af7aafSAndrei Emeltchenko chan->local_acc_lat = le32_to_cpu(efs.acc_lat); 280266af7aafSAndrei Emeltchenko chan->local_flush_to = 280366af7aafSAndrei Emeltchenko le32_to_cpu(efs.flush_to); 280466af7aafSAndrei Emeltchenko } 28050a708f8fSGustavo F. Padovan break; 280666af7aafSAndrei Emeltchenko 28070a708f8fSGustavo F. Padovan case L2CAP_MODE_STREAMING: 280847d1ec61SGustavo F. Padovan chan->mps = le16_to_cpu(rfc.max_pdu_size); 28090a708f8fSGustavo F. Padovan } 28100a708f8fSGustavo F. Padovan } 28110a708f8fSGustavo F. Padovan 2812fe4128e0SGustavo F. Padovan req->dcid = cpu_to_le16(chan->dcid); 28130a708f8fSGustavo F. Padovan req->flags = cpu_to_le16(0x0000); 28140a708f8fSGustavo F. Padovan 28150a708f8fSGustavo F. Padovan return ptr - data; 28160a708f8fSGustavo F. Padovan } 28170a708f8fSGustavo F. Padovan 2818fe4128e0SGustavo F. Padovan static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags) 28190a708f8fSGustavo F. Padovan { 28200a708f8fSGustavo F. Padovan struct l2cap_conf_rsp *rsp = data; 28210a708f8fSGustavo F. Padovan void *ptr = rsp->data; 28220a708f8fSGustavo F. Padovan 2823fe4128e0SGustavo F. Padovan BT_DBG("chan %p", chan); 28240a708f8fSGustavo F. Padovan 2825fe4128e0SGustavo F. Padovan rsp->scid = cpu_to_le16(chan->dcid); 28260a708f8fSGustavo F. Padovan rsp->result = cpu_to_le16(result); 28270a708f8fSGustavo F. Padovan rsp->flags = cpu_to_le16(flags); 28280a708f8fSGustavo F. Padovan 28290a708f8fSGustavo F. Padovan return ptr - data; 28300a708f8fSGustavo F. Padovan } 28310a708f8fSGustavo F. Padovan 28328c1d787bSGustavo F. Padovan void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) 2833710f9b0aSGustavo F. Padovan { 2834710f9b0aSGustavo F. Padovan struct l2cap_conn_rsp rsp; 28358c1d787bSGustavo F. Padovan struct l2cap_conn *conn = chan->conn; 2836710f9b0aSGustavo F. Padovan u8 buf[128]; 2837710f9b0aSGustavo F. Padovan 2838fe4128e0SGustavo F. Padovan rsp.scid = cpu_to_le16(chan->dcid); 2839fe4128e0SGustavo F. Padovan rsp.dcid = cpu_to_le16(chan->scid); 2840710f9b0aSGustavo F. Padovan rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); 2841710f9b0aSGustavo F. Padovan rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); 2842710f9b0aSGustavo F. Padovan l2cap_send_cmd(conn, chan->ident, 2843710f9b0aSGustavo F. Padovan L2CAP_CONN_RSP, sizeof(rsp), &rsp); 2844710f9b0aSGustavo F. Padovan 2845c1360a1cSGustavo F. Padovan if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) 2846710f9b0aSGustavo F. Padovan return; 2847710f9b0aSGustavo F. Padovan 2848710f9b0aSGustavo F. Padovan l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, 2849710f9b0aSGustavo F. Padovan l2cap_build_conf_req(chan, buf), buf); 2850710f9b0aSGustavo F. Padovan chan->num_conf_req++; 2851710f9b0aSGustavo F. Padovan } 2852710f9b0aSGustavo F. Padovan 285347d1ec61SGustavo F. Padovan static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) 28540a708f8fSGustavo F. Padovan { 28550a708f8fSGustavo F. Padovan int type, olen; 28560a708f8fSGustavo F. Padovan unsigned long val; 28570a708f8fSGustavo F. Padovan struct l2cap_conf_rfc rfc; 28580a708f8fSGustavo F. Padovan 285947d1ec61SGustavo F. Padovan BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len); 28600a708f8fSGustavo F. Padovan 28610c1bc5c6SGustavo F. Padovan if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING)) 28620a708f8fSGustavo F. Padovan return; 28630a708f8fSGustavo F. Padovan 28640a708f8fSGustavo F. Padovan while (len >= L2CAP_CONF_OPT_SIZE) { 28650a708f8fSGustavo F. Padovan len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); 28660a708f8fSGustavo F. Padovan 28670a708f8fSGustavo F. Padovan switch (type) { 28680a708f8fSGustavo F. Padovan case L2CAP_CONF_RFC: 28690a708f8fSGustavo F. Padovan if (olen == sizeof(rfc)) 28700a708f8fSGustavo F. Padovan memcpy(&rfc, (void *)val, olen); 28710a708f8fSGustavo F. Padovan goto done; 28720a708f8fSGustavo F. Padovan } 28730a708f8fSGustavo F. Padovan } 28740a708f8fSGustavo F. Padovan 287536e999a8SMat Martineau /* Use sane default values in case a misbehaving remote device 287636e999a8SMat Martineau * did not send an RFC option. 287736e999a8SMat Martineau */ 287836e999a8SMat Martineau rfc.mode = chan->mode; 287936e999a8SMat Martineau rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); 288036e999a8SMat Martineau rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); 288136e999a8SMat Martineau rfc.max_pdu_size = cpu_to_le16(chan->imtu); 288236e999a8SMat Martineau 288336e999a8SMat Martineau BT_ERR("Expected RFC option was not found, using defaults"); 288436e999a8SMat Martineau 28850a708f8fSGustavo F. Padovan done: 28860a708f8fSGustavo F. Padovan switch (rfc.mode) { 28870a708f8fSGustavo F. Padovan case L2CAP_MODE_ERTM: 288847d1ec61SGustavo F. Padovan chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); 288947d1ec61SGustavo F. Padovan chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); 289047d1ec61SGustavo F. Padovan chan->mps = le16_to_cpu(rfc.max_pdu_size); 28910a708f8fSGustavo F. Padovan break; 28920a708f8fSGustavo F. Padovan case L2CAP_MODE_STREAMING: 289347d1ec61SGustavo F. Padovan chan->mps = le16_to_cpu(rfc.max_pdu_size); 28940a708f8fSGustavo F. Padovan } 28950a708f8fSGustavo F. Padovan } 28960a708f8fSGustavo F. Padovan 28970a708f8fSGustavo F. Padovan static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 28980a708f8fSGustavo F. Padovan { 2899e2fd318eSIlia Kolomisnky struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data; 29000a708f8fSGustavo F. Padovan 2901e2fd318eSIlia Kolomisnky if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD) 29020a708f8fSGustavo F. Padovan return 0; 29030a708f8fSGustavo F. Padovan 29040a708f8fSGustavo F. Padovan if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) && 29050a708f8fSGustavo F. Padovan cmd->ident == conn->info_ident) { 290617cd3f37SUlisses Furquim cancel_delayed_work(&conn->info_timer); 29070a708f8fSGustavo F. Padovan 29080a708f8fSGustavo F. Padovan conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; 29090a708f8fSGustavo F. Padovan conn->info_ident = 0; 29100a708f8fSGustavo F. Padovan 29110a708f8fSGustavo F. Padovan l2cap_conn_start(conn); 29120a708f8fSGustavo F. Padovan } 29130a708f8fSGustavo F. Padovan 29140a708f8fSGustavo F. Padovan return 0; 29150a708f8fSGustavo F. Padovan } 29160a708f8fSGustavo F. Padovan 29170a708f8fSGustavo F. Padovan static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 29180a708f8fSGustavo F. Padovan { 29190a708f8fSGustavo F. Padovan struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; 29200a708f8fSGustavo F. Padovan struct l2cap_conn_rsp rsp; 292123691d75SGustavo F. Padovan struct l2cap_chan *chan = NULL, *pchan; 29220a708f8fSGustavo F. Padovan struct sock *parent, *sk = NULL; 29230a708f8fSGustavo F. Padovan int result, status = L2CAP_CS_NO_INFO; 29240a708f8fSGustavo F. Padovan 29250a708f8fSGustavo F. Padovan u16 dcid = 0, scid = __le16_to_cpu(req->scid); 29260a708f8fSGustavo F. Padovan __le16 psm = req->psm; 29270a708f8fSGustavo F. Padovan 2928097db76cSAndrei Emeltchenko BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid); 29290a708f8fSGustavo F. Padovan 29300a708f8fSGustavo F. Padovan /* Check if we have socket listening on psm */ 2931c2287681SIdo Yariv pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src, conn->dst); 293223691d75SGustavo F. Padovan if (!pchan) { 29330a708f8fSGustavo F. Padovan result = L2CAP_CR_BAD_PSM; 29340a708f8fSGustavo F. Padovan goto sendresp; 29350a708f8fSGustavo F. Padovan } 29360a708f8fSGustavo F. Padovan 293723691d75SGustavo F. Padovan parent = pchan->sk; 293823691d75SGustavo F. Padovan 29393df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 2940aa2ac881SGustavo F. Padovan lock_sock(parent); 29410a708f8fSGustavo F. Padovan 29420a708f8fSGustavo F. Padovan /* Check if the ACL is secure enough (if not SDP) */ 29430a708f8fSGustavo F. Padovan if (psm != cpu_to_le16(0x0001) && 29440a708f8fSGustavo F. Padovan !hci_conn_check_link_mode(conn->hcon)) { 29459f5a0d7bSAndrei Emeltchenko conn->disc_reason = HCI_ERROR_AUTH_FAILURE; 29460a708f8fSGustavo F. Padovan result = L2CAP_CR_SEC_BLOCK; 29470a708f8fSGustavo F. Padovan goto response; 29480a708f8fSGustavo F. Padovan } 29490a708f8fSGustavo F. Padovan 29500a708f8fSGustavo F. Padovan result = L2CAP_CR_NO_MEM; 29510a708f8fSGustavo F. Padovan 29520a708f8fSGustavo F. Padovan /* Check for backlog size */ 29530a708f8fSGustavo F. Padovan if (sk_acceptq_is_full(parent)) { 29540a708f8fSGustavo F. Padovan BT_DBG("backlog full %d", parent->sk_ack_backlog); 29550a708f8fSGustavo F. Padovan goto response; 29560a708f8fSGustavo F. Padovan } 29570a708f8fSGustavo F. Padovan 295880808e43SGustavo F. Padovan chan = pchan->ops->new_connection(pchan->data); 295980808e43SGustavo F. Padovan if (!chan) 29600a708f8fSGustavo F. Padovan goto response; 29610a708f8fSGustavo F. Padovan 296280808e43SGustavo F. Padovan sk = chan->sk; 296380808e43SGustavo F. Padovan 29640a708f8fSGustavo F. Padovan /* Check if we already have channel with that dcid */ 2965baa7e1faSGustavo F. Padovan if (__l2cap_get_chan_by_dcid(conn, scid)) { 29660a708f8fSGustavo F. Padovan sock_set_flag(sk, SOCK_ZAPPED); 2967ba3bd0eeSGustavo F. Padovan chan->ops->close(chan->data); 29680a708f8fSGustavo F. Padovan goto response; 29690a708f8fSGustavo F. Padovan } 29700a708f8fSGustavo F. Padovan 29710a708f8fSGustavo F. Padovan hci_conn_hold(conn->hcon); 29720a708f8fSGustavo F. Padovan 29730a708f8fSGustavo F. Padovan bacpy(&bt_sk(sk)->src, conn->src); 29740a708f8fSGustavo F. Padovan bacpy(&bt_sk(sk)->dst, conn->dst); 2975fe4128e0SGustavo F. Padovan chan->psm = psm; 2976fe4128e0SGustavo F. Padovan chan->dcid = scid; 29770a708f8fSGustavo F. Padovan 2978d1010240SGustavo F. Padovan bt_accept_enqueue(parent, sk); 2979d1010240SGustavo F. Padovan 29806be36555SAndrei Emeltchenko __l2cap_chan_add(conn, chan); 298148454079SGustavo F. Padovan 2982fe4128e0SGustavo F. Padovan dcid = chan->scid; 29830a708f8fSGustavo F. Padovan 2984c9b66675SGustavo F. Padovan __set_chan_timer(chan, sk->sk_sndtimeo); 29850a708f8fSGustavo F. Padovan 2986fc7f8a7eSGustavo F. Padovan chan->ident = cmd->ident; 29870a708f8fSGustavo F. Padovan 29880a708f8fSGustavo F. Padovan if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { 2989d45fc423SGustavo F. Padovan if (l2cap_chan_check_security(chan)) { 29900a708f8fSGustavo F. Padovan if (bt_sk(sk)->defer_setup) { 29910e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_CONNECT2); 29920a708f8fSGustavo F. Padovan result = L2CAP_CR_PEND; 29930a708f8fSGustavo F. Padovan status = L2CAP_CS_AUTHOR_PEND; 29940a708f8fSGustavo F. Padovan parent->sk_data_ready(parent, 0); 29950a708f8fSGustavo F. Padovan } else { 29960e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_CONFIG); 29970a708f8fSGustavo F. Padovan result = L2CAP_CR_SUCCESS; 29980a708f8fSGustavo F. Padovan status = L2CAP_CS_NO_INFO; 29990a708f8fSGustavo F. Padovan } 30000a708f8fSGustavo F. Padovan } else { 30010e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_CONNECT2); 30020a708f8fSGustavo F. Padovan result = L2CAP_CR_PEND; 30030a708f8fSGustavo F. Padovan status = L2CAP_CS_AUTHEN_PEND; 30040a708f8fSGustavo F. Padovan } 30050a708f8fSGustavo F. Padovan } else { 30060e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_CONNECT2); 30070a708f8fSGustavo F. Padovan result = L2CAP_CR_PEND; 30080a708f8fSGustavo F. Padovan status = L2CAP_CS_NO_INFO; 30090a708f8fSGustavo F. Padovan } 30100a708f8fSGustavo F. Padovan 30110a708f8fSGustavo F. Padovan response: 3012aa2ac881SGustavo F. Padovan release_sock(parent); 30133df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 30140a708f8fSGustavo F. Padovan 30150a708f8fSGustavo F. Padovan sendresp: 30160a708f8fSGustavo F. Padovan rsp.scid = cpu_to_le16(scid); 30170a708f8fSGustavo F. Padovan rsp.dcid = cpu_to_le16(dcid); 30180a708f8fSGustavo F. Padovan rsp.result = cpu_to_le16(result); 30190a708f8fSGustavo F. Padovan rsp.status = cpu_to_le16(status); 30200a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); 30210a708f8fSGustavo F. Padovan 30220a708f8fSGustavo F. Padovan if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) { 30230a708f8fSGustavo F. Padovan struct l2cap_info_req info; 30240a708f8fSGustavo F. Padovan info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); 30250a708f8fSGustavo F. Padovan 30260a708f8fSGustavo F. Padovan conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; 30270a708f8fSGustavo F. Padovan conn->info_ident = l2cap_get_ident(conn); 30280a708f8fSGustavo F. Padovan 3029ba13ccd9SMarcel Holtmann schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT); 30300a708f8fSGustavo F. Padovan 30310a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, conn->info_ident, 30320a708f8fSGustavo F. Padovan L2CAP_INFO_REQ, sizeof(info), &info); 30330a708f8fSGustavo F. Padovan } 30340a708f8fSGustavo F. Padovan 3035c1360a1cSGustavo F. Padovan if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) && 30360a708f8fSGustavo F. Padovan result == L2CAP_CR_SUCCESS) { 30370a708f8fSGustavo F. Padovan u8 buf[128]; 3038c1360a1cSGustavo F. Padovan set_bit(CONF_REQ_SENT, &chan->conf_state); 30390a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, 304073ffa904SGustavo F. Padovan l2cap_build_conf_req(chan, buf), buf); 304173ffa904SGustavo F. Padovan chan->num_conf_req++; 30420a708f8fSGustavo F. Padovan } 30430a708f8fSGustavo F. Padovan 30440a708f8fSGustavo F. Padovan return 0; 30450a708f8fSGustavo F. Padovan } 30460a708f8fSGustavo F. Padovan 30470a708f8fSGustavo F. Padovan static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 30480a708f8fSGustavo F. Padovan { 30490a708f8fSGustavo F. Padovan struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; 30500a708f8fSGustavo F. Padovan u16 scid, dcid, result, status; 305148454079SGustavo F. Padovan struct l2cap_chan *chan; 30520a708f8fSGustavo F. Padovan u8 req[128]; 30533df91ea2SAndrei Emeltchenko int err; 30540a708f8fSGustavo F. Padovan 30550a708f8fSGustavo F. Padovan scid = __le16_to_cpu(rsp->scid); 30560a708f8fSGustavo F. Padovan dcid = __le16_to_cpu(rsp->dcid); 30570a708f8fSGustavo F. Padovan result = __le16_to_cpu(rsp->result); 30580a708f8fSGustavo F. Padovan status = __le16_to_cpu(rsp->status); 30590a708f8fSGustavo F. Padovan 30601b009c98SAndrei Emeltchenko BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", 30611b009c98SAndrei Emeltchenko dcid, scid, result, status); 30620a708f8fSGustavo F. Padovan 30633df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 30643df91ea2SAndrei Emeltchenko 30650a708f8fSGustavo F. Padovan if (scid) { 30663df91ea2SAndrei Emeltchenko chan = __l2cap_get_chan_by_scid(conn, scid); 30673df91ea2SAndrei Emeltchenko if (!chan) { 30683df91ea2SAndrei Emeltchenko err = -EFAULT; 30693df91ea2SAndrei Emeltchenko goto unlock; 30703df91ea2SAndrei Emeltchenko } 30710a708f8fSGustavo F. Padovan } else { 30723df91ea2SAndrei Emeltchenko chan = __l2cap_get_chan_by_ident(conn, cmd->ident); 30733df91ea2SAndrei Emeltchenko if (!chan) { 30743df91ea2SAndrei Emeltchenko err = -EFAULT; 30753df91ea2SAndrei Emeltchenko goto unlock; 30763df91ea2SAndrei Emeltchenko } 30770a708f8fSGustavo F. Padovan } 30780a708f8fSGustavo F. Padovan 30793df91ea2SAndrei Emeltchenko err = 0; 30803df91ea2SAndrei Emeltchenko 30816be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 308248454079SGustavo F. Padovan 30830a708f8fSGustavo F. Padovan switch (result) { 30840a708f8fSGustavo F. Padovan case L2CAP_CR_SUCCESS: 308589bc500eSGustavo F. Padovan l2cap_state_change(chan, BT_CONFIG); 3086fc7f8a7eSGustavo F. Padovan chan->ident = 0; 3087fe4128e0SGustavo F. Padovan chan->dcid = dcid; 3088c1360a1cSGustavo F. Padovan clear_bit(CONF_CONNECT_PEND, &chan->conf_state); 30890a708f8fSGustavo F. Padovan 3090c1360a1cSGustavo F. Padovan if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) 30910a708f8fSGustavo F. Padovan break; 30920a708f8fSGustavo F. Padovan 30930a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, 309473ffa904SGustavo F. Padovan l2cap_build_conf_req(chan, req), req); 309573ffa904SGustavo F. Padovan chan->num_conf_req++; 30960a708f8fSGustavo F. Padovan break; 30970a708f8fSGustavo F. Padovan 30980a708f8fSGustavo F. Padovan case L2CAP_CR_PEND: 3099c1360a1cSGustavo F. Padovan set_bit(CONF_CONNECT_PEND, &chan->conf_state); 31000a708f8fSGustavo F. Padovan break; 31010a708f8fSGustavo F. Padovan 31020a708f8fSGustavo F. Padovan default: 310348454079SGustavo F. Padovan l2cap_chan_del(chan, ECONNREFUSED); 31040a708f8fSGustavo F. Padovan break; 31050a708f8fSGustavo F. Padovan } 31060a708f8fSGustavo F. Padovan 31076be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 31083df91ea2SAndrei Emeltchenko 31093df91ea2SAndrei Emeltchenko unlock: 31103df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 31113df91ea2SAndrei Emeltchenko 31123df91ea2SAndrei Emeltchenko return err; 31130a708f8fSGustavo F. Padovan } 31140a708f8fSGustavo F. Padovan 311547d1ec61SGustavo F. Padovan static inline void set_default_fcs(struct l2cap_chan *chan) 31160a708f8fSGustavo F. Padovan { 31170a708f8fSGustavo F. Padovan /* FCS is enabled only in ERTM or streaming mode, if one or both 31180a708f8fSGustavo F. Padovan * sides request it. 31190a708f8fSGustavo F. Padovan */ 31200c1bc5c6SGustavo F. Padovan if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING) 312147d1ec61SGustavo F. Padovan chan->fcs = L2CAP_FCS_NONE; 3122c1360a1cSGustavo F. Padovan else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) 312347d1ec61SGustavo F. Padovan chan->fcs = L2CAP_FCS_CRC16; 31240a708f8fSGustavo F. Padovan } 31250a708f8fSGustavo F. Padovan 31260a708f8fSGustavo F. Padovan static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) 31270a708f8fSGustavo F. Padovan { 31280a708f8fSGustavo F. Padovan struct l2cap_conf_req *req = (struct l2cap_conf_req *) data; 31290a708f8fSGustavo F. Padovan u16 dcid, flags; 31300a708f8fSGustavo F. Padovan u8 rsp[64]; 313148454079SGustavo F. Padovan struct l2cap_chan *chan; 31323c588192SMat Martineau int len, err = 0; 31330a708f8fSGustavo F. Padovan 31340a708f8fSGustavo F. Padovan dcid = __le16_to_cpu(req->dcid); 31350a708f8fSGustavo F. Padovan flags = __le16_to_cpu(req->flags); 31360a708f8fSGustavo F. Padovan 31370a708f8fSGustavo F. Padovan BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); 31380a708f8fSGustavo F. Padovan 3139baa7e1faSGustavo F. Padovan chan = l2cap_get_chan_by_scid(conn, dcid); 314048454079SGustavo F. Padovan if (!chan) 31410a708f8fSGustavo F. Padovan return -ENOENT; 31420a708f8fSGustavo F. Padovan 31436be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 314448454079SGustavo F. Padovan 3145033b1142SDavid S. Miller if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { 3146e2fd318eSIlia Kolomisnky struct l2cap_cmd_rej_cid rej; 31470a708f8fSGustavo F. Padovan 3148e2fd318eSIlia Kolomisnky rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID); 3149e2fd318eSIlia Kolomisnky rej.scid = cpu_to_le16(chan->scid); 3150e2fd318eSIlia Kolomisnky rej.dcid = cpu_to_le16(chan->dcid); 3151e2fd318eSIlia Kolomisnky 31520a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ, 31530a708f8fSGustavo F. Padovan sizeof(rej), &rej); 31540a708f8fSGustavo F. Padovan goto unlock; 31550a708f8fSGustavo F. Padovan } 31560a708f8fSGustavo F. Padovan 31570a708f8fSGustavo F. Padovan /* Reject if config buffer is too small. */ 31580a708f8fSGustavo F. Padovan len = cmd_len - sizeof(*req); 31597ac28817SDan Rosenberg if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) { 31600a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, 3161fe4128e0SGustavo F. Padovan l2cap_build_conf_rsp(chan, rsp, 31620a708f8fSGustavo F. Padovan L2CAP_CONF_REJECT, flags), rsp); 31630a708f8fSGustavo F. Padovan goto unlock; 31640a708f8fSGustavo F. Padovan } 31650a708f8fSGustavo F. Padovan 31660a708f8fSGustavo F. Padovan /* Store config. */ 316773ffa904SGustavo F. Padovan memcpy(chan->conf_req + chan->conf_len, req->data, len); 316873ffa904SGustavo F. Padovan chan->conf_len += len; 31690a708f8fSGustavo F. Padovan 31700a708f8fSGustavo F. Padovan if (flags & 0x0001) { 31710a708f8fSGustavo F. Padovan /* Incomplete config. Send empty response. */ 31720a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, 3173fe4128e0SGustavo F. Padovan l2cap_build_conf_rsp(chan, rsp, 31740a708f8fSGustavo F. Padovan L2CAP_CONF_SUCCESS, 0x0001), rsp); 31750a708f8fSGustavo F. Padovan goto unlock; 31760a708f8fSGustavo F. Padovan } 31770a708f8fSGustavo F. Padovan 31780a708f8fSGustavo F. Padovan /* Complete config. */ 317973ffa904SGustavo F. Padovan len = l2cap_parse_conf_req(chan, rsp); 31800a708f8fSGustavo F. Padovan if (len < 0) { 3181e92c8e70SGustavo F. Padovan l2cap_send_disconn_req(conn, chan, ECONNRESET); 31820a708f8fSGustavo F. Padovan goto unlock; 31830a708f8fSGustavo F. Padovan } 31840a708f8fSGustavo F. Padovan 31850a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); 318673ffa904SGustavo F. Padovan chan->num_conf_rsp++; 31870a708f8fSGustavo F. Padovan 31880a708f8fSGustavo F. Padovan /* Reset config buffer. */ 318973ffa904SGustavo F. Padovan chan->conf_len = 0; 31900a708f8fSGustavo F. Padovan 3191c1360a1cSGustavo F. Padovan if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) 31920a708f8fSGustavo F. Padovan goto unlock; 31930a708f8fSGustavo F. Padovan 3194c1360a1cSGustavo F. Padovan if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) { 319547d1ec61SGustavo F. Padovan set_default_fcs(chan); 31960a708f8fSGustavo F. Padovan 319789bc500eSGustavo F. Padovan l2cap_state_change(chan, BT_CONNECTED); 31980a708f8fSGustavo F. Padovan 3199105bdf9eSMat Martineau if (chan->mode == L2CAP_MODE_ERTM || 3200105bdf9eSMat Martineau chan->mode == L2CAP_MODE_STREAMING) 32013c588192SMat Martineau err = l2cap_ertm_init(chan); 32020a708f8fSGustavo F. Padovan 32033c588192SMat Martineau if (err < 0) 32043c588192SMat Martineau l2cap_send_disconn_req(chan->conn, chan, -err); 32053c588192SMat Martineau else 3206cf4cd009SAndrei Emeltchenko l2cap_chan_ready(chan); 32073c588192SMat Martineau 32080a708f8fSGustavo F. Padovan goto unlock; 32090a708f8fSGustavo F. Padovan } 32100a708f8fSGustavo F. Padovan 3211c1360a1cSGustavo F. Padovan if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) { 32120a708f8fSGustavo F. Padovan u8 buf[64]; 32130a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, 321473ffa904SGustavo F. Padovan l2cap_build_conf_req(chan, buf), buf); 321573ffa904SGustavo F. Padovan chan->num_conf_req++; 32160a708f8fSGustavo F. Padovan } 32170a708f8fSGustavo F. Padovan 32180e8b207eSAndrei Emeltchenko /* Got Conf Rsp PENDING from remote side and asume we sent 32190e8b207eSAndrei Emeltchenko Conf Rsp PENDING in the code above */ 32200e8b207eSAndrei Emeltchenko if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) && 32210e8b207eSAndrei Emeltchenko test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) { 32220e8b207eSAndrei Emeltchenko 32230e8b207eSAndrei Emeltchenko /* check compatibility */ 32240e8b207eSAndrei Emeltchenko 32250e8b207eSAndrei Emeltchenko clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state); 32260e8b207eSAndrei Emeltchenko set_bit(CONF_OUTPUT_DONE, &chan->conf_state); 32270e8b207eSAndrei Emeltchenko 32280e8b207eSAndrei Emeltchenko l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, 32290e8b207eSAndrei Emeltchenko l2cap_build_conf_rsp(chan, rsp, 32300e8b207eSAndrei Emeltchenko L2CAP_CONF_SUCCESS, 0x0000), rsp); 32310e8b207eSAndrei Emeltchenko } 32320e8b207eSAndrei Emeltchenko 32330a708f8fSGustavo F. Padovan unlock: 32346be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 32353c588192SMat Martineau return err; 32360a708f8fSGustavo F. Padovan } 32370a708f8fSGustavo F. Padovan 32380a708f8fSGustavo F. Padovan static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 32390a708f8fSGustavo F. Padovan { 32400a708f8fSGustavo F. Padovan struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; 32410a708f8fSGustavo F. Padovan u16 scid, flags, result; 324248454079SGustavo F. Padovan struct l2cap_chan *chan; 324361386cbaSAndrei Emeltchenko int len = le16_to_cpu(cmd->len) - sizeof(*rsp); 32443c588192SMat Martineau int err = 0; 32450a708f8fSGustavo F. Padovan 32460a708f8fSGustavo F. Padovan scid = __le16_to_cpu(rsp->scid); 32470a708f8fSGustavo F. Padovan flags = __le16_to_cpu(rsp->flags); 32480a708f8fSGustavo F. Padovan result = __le16_to_cpu(rsp->result); 32490a708f8fSGustavo F. Padovan 325061386cbaSAndrei Emeltchenko BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x len %d", scid, flags, 325161386cbaSAndrei Emeltchenko result, len); 32520a708f8fSGustavo F. Padovan 3253baa7e1faSGustavo F. Padovan chan = l2cap_get_chan_by_scid(conn, scid); 325448454079SGustavo F. Padovan if (!chan) 32550a708f8fSGustavo F. Padovan return 0; 32560a708f8fSGustavo F. Padovan 32576be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 325848454079SGustavo F. Padovan 32590a708f8fSGustavo F. Padovan switch (result) { 32600a708f8fSGustavo F. Padovan case L2CAP_CONF_SUCCESS: 326147d1ec61SGustavo F. Padovan l2cap_conf_rfc_get(chan, rsp->data, len); 32620e8b207eSAndrei Emeltchenko clear_bit(CONF_REM_CONF_PEND, &chan->conf_state); 32630a708f8fSGustavo F. Padovan break; 32640a708f8fSGustavo F. Padovan 32650e8b207eSAndrei Emeltchenko case L2CAP_CONF_PENDING: 32660e8b207eSAndrei Emeltchenko set_bit(CONF_REM_CONF_PEND, &chan->conf_state); 32670e8b207eSAndrei Emeltchenko 32680e8b207eSAndrei Emeltchenko if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) { 32690e8b207eSAndrei Emeltchenko char buf[64]; 32700e8b207eSAndrei Emeltchenko 32710e8b207eSAndrei Emeltchenko len = l2cap_parse_conf_rsp(chan, rsp->data, len, 32720e8b207eSAndrei Emeltchenko buf, &result); 32730e8b207eSAndrei Emeltchenko if (len < 0) { 32740e8b207eSAndrei Emeltchenko l2cap_send_disconn_req(conn, chan, ECONNRESET); 32750e8b207eSAndrei Emeltchenko goto done; 32760e8b207eSAndrei Emeltchenko } 32770e8b207eSAndrei Emeltchenko 32780e8b207eSAndrei Emeltchenko /* check compatibility */ 32790e8b207eSAndrei Emeltchenko 32800e8b207eSAndrei Emeltchenko clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state); 32810e8b207eSAndrei Emeltchenko set_bit(CONF_OUTPUT_DONE, &chan->conf_state); 32820e8b207eSAndrei Emeltchenko 32830e8b207eSAndrei Emeltchenko l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, 32840e8b207eSAndrei Emeltchenko l2cap_build_conf_rsp(chan, buf, 32850e8b207eSAndrei Emeltchenko L2CAP_CONF_SUCCESS, 0x0000), buf); 32860e8b207eSAndrei Emeltchenko } 32870e8b207eSAndrei Emeltchenko goto done; 32880e8b207eSAndrei Emeltchenko 32890a708f8fSGustavo F. Padovan case L2CAP_CONF_UNACCEPT: 329073ffa904SGustavo F. Padovan if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { 32910a708f8fSGustavo F. Padovan char req[64]; 32920a708f8fSGustavo F. Padovan 32930a708f8fSGustavo F. Padovan if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { 3294e92c8e70SGustavo F. Padovan l2cap_send_disconn_req(conn, chan, ECONNRESET); 32950a708f8fSGustavo F. Padovan goto done; 32960a708f8fSGustavo F. Padovan } 32970a708f8fSGustavo F. Padovan 32980a708f8fSGustavo F. Padovan /* throw out any old stored conf requests */ 32990a708f8fSGustavo F. Padovan result = L2CAP_CONF_SUCCESS; 3300b4450035SGustavo F. Padovan len = l2cap_parse_conf_rsp(chan, rsp->data, len, 3301b4450035SGustavo F. Padovan req, &result); 33020a708f8fSGustavo F. Padovan if (len < 0) { 3303e92c8e70SGustavo F. Padovan l2cap_send_disconn_req(conn, chan, ECONNRESET); 33040a708f8fSGustavo F. Padovan goto done; 33050a708f8fSGustavo F. Padovan } 33060a708f8fSGustavo F. Padovan 33070a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, l2cap_get_ident(conn), 33080a708f8fSGustavo F. Padovan L2CAP_CONF_REQ, len, req); 330973ffa904SGustavo F. Padovan chan->num_conf_req++; 33100a708f8fSGustavo F. Padovan if (result != L2CAP_CONF_SUCCESS) 33110a708f8fSGustavo F. Padovan goto done; 33120a708f8fSGustavo F. Padovan break; 33130a708f8fSGustavo F. Padovan } 33140a708f8fSGustavo F. Padovan 33150a708f8fSGustavo F. Padovan default: 33166be36555SAndrei Emeltchenko l2cap_chan_set_err(chan, ECONNRESET); 33172e0052e4SAndrei Emeltchenko 3318ba13ccd9SMarcel Holtmann __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT); 3319e92c8e70SGustavo F. Padovan l2cap_send_disconn_req(conn, chan, ECONNRESET); 33200a708f8fSGustavo F. Padovan goto done; 33210a708f8fSGustavo F. Padovan } 33220a708f8fSGustavo F. Padovan 33230a708f8fSGustavo F. Padovan if (flags & 0x01) 33240a708f8fSGustavo F. Padovan goto done; 33250a708f8fSGustavo F. Padovan 3326c1360a1cSGustavo F. Padovan set_bit(CONF_INPUT_DONE, &chan->conf_state); 33270a708f8fSGustavo F. Padovan 3328c1360a1cSGustavo F. Padovan if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) { 332947d1ec61SGustavo F. Padovan set_default_fcs(chan); 33300a708f8fSGustavo F. Padovan 333189bc500eSGustavo F. Padovan l2cap_state_change(chan, BT_CONNECTED); 3332105bdf9eSMat Martineau if (chan->mode == L2CAP_MODE_ERTM || 3333105bdf9eSMat Martineau chan->mode == L2CAP_MODE_STREAMING) 33343c588192SMat Martineau err = l2cap_ertm_init(chan); 33350a708f8fSGustavo F. Padovan 33363c588192SMat Martineau if (err < 0) 33373c588192SMat Martineau l2cap_send_disconn_req(chan->conn, chan, -err); 33383c588192SMat Martineau else 3339cf4cd009SAndrei Emeltchenko l2cap_chan_ready(chan); 33400a708f8fSGustavo F. Padovan } 33410a708f8fSGustavo F. Padovan 33420a708f8fSGustavo F. Padovan done: 33436be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 33443c588192SMat Martineau return err; 33450a708f8fSGustavo F. Padovan } 33460a708f8fSGustavo F. Padovan 33470a708f8fSGustavo F. Padovan static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 33480a708f8fSGustavo F. Padovan { 33490a708f8fSGustavo F. Padovan struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data; 33500a708f8fSGustavo F. Padovan struct l2cap_disconn_rsp rsp; 33510a708f8fSGustavo F. Padovan u16 dcid, scid; 335248454079SGustavo F. Padovan struct l2cap_chan *chan; 33530a708f8fSGustavo F. Padovan struct sock *sk; 33540a708f8fSGustavo F. Padovan 33550a708f8fSGustavo F. Padovan scid = __le16_to_cpu(req->scid); 33560a708f8fSGustavo F. Padovan dcid = __le16_to_cpu(req->dcid); 33570a708f8fSGustavo F. Padovan 33580a708f8fSGustavo F. Padovan BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); 33590a708f8fSGustavo F. Padovan 33603df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 33613df91ea2SAndrei Emeltchenko 33623df91ea2SAndrei Emeltchenko chan = __l2cap_get_chan_by_scid(conn, dcid); 33633df91ea2SAndrei Emeltchenko if (!chan) { 33643df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 33650a708f8fSGustavo F. Padovan return 0; 33663df91ea2SAndrei Emeltchenko } 33670a708f8fSGustavo F. Padovan 33686be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 33696be36555SAndrei Emeltchenko 337048454079SGustavo F. Padovan sk = chan->sk; 337148454079SGustavo F. Padovan 3372fe4128e0SGustavo F. Padovan rsp.dcid = cpu_to_le16(chan->scid); 3373fe4128e0SGustavo F. Padovan rsp.scid = cpu_to_le16(chan->dcid); 33740a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); 33750a708f8fSGustavo F. Padovan 33766be36555SAndrei Emeltchenko lock_sock(sk); 33770a708f8fSGustavo F. Padovan sk->sk_shutdown = SHUTDOWN_MASK; 33786be36555SAndrei Emeltchenko release_sock(sk); 33790a708f8fSGustavo F. Padovan 3380*61d6ef3eSMat Martineau l2cap_chan_hold(chan); 338148454079SGustavo F. Padovan l2cap_chan_del(chan, ECONNRESET); 33826be36555SAndrei Emeltchenko 33836be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 33840a708f8fSGustavo F. Padovan 3385ba3bd0eeSGustavo F. Padovan chan->ops->close(chan->data); 3386*61d6ef3eSMat Martineau l2cap_chan_put(chan); 33873df91ea2SAndrei Emeltchenko 33883df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 33893df91ea2SAndrei Emeltchenko 33900a708f8fSGustavo F. Padovan return 0; 33910a708f8fSGustavo F. Padovan } 33920a708f8fSGustavo F. Padovan 33930a708f8fSGustavo F. Padovan static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 33940a708f8fSGustavo F. Padovan { 33950a708f8fSGustavo F. Padovan struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data; 33960a708f8fSGustavo F. Padovan u16 dcid, scid; 339748454079SGustavo F. Padovan struct l2cap_chan *chan; 33980a708f8fSGustavo F. Padovan 33990a708f8fSGustavo F. Padovan scid = __le16_to_cpu(rsp->scid); 34000a708f8fSGustavo F. Padovan dcid = __le16_to_cpu(rsp->dcid); 34010a708f8fSGustavo F. Padovan 34020a708f8fSGustavo F. Padovan BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); 34030a708f8fSGustavo F. Padovan 34043df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 34053df91ea2SAndrei Emeltchenko 34063df91ea2SAndrei Emeltchenko chan = __l2cap_get_chan_by_scid(conn, scid); 34073df91ea2SAndrei Emeltchenko if (!chan) { 34083df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 34090a708f8fSGustavo F. Padovan return 0; 34103df91ea2SAndrei Emeltchenko } 34110a708f8fSGustavo F. Padovan 34126be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 341348454079SGustavo F. Padovan 3414*61d6ef3eSMat Martineau l2cap_chan_hold(chan); 341548454079SGustavo F. Padovan l2cap_chan_del(chan, 0); 34166be36555SAndrei Emeltchenko 34176be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 34180a708f8fSGustavo F. Padovan 3419ba3bd0eeSGustavo F. Padovan chan->ops->close(chan->data); 3420*61d6ef3eSMat Martineau l2cap_chan_put(chan); 34213df91ea2SAndrei Emeltchenko 34223df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 34233df91ea2SAndrei Emeltchenko 34240a708f8fSGustavo F. Padovan return 0; 34250a708f8fSGustavo F. Padovan } 34260a708f8fSGustavo F. Padovan 34270a708f8fSGustavo F. Padovan static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 34280a708f8fSGustavo F. Padovan { 34290a708f8fSGustavo F. Padovan struct l2cap_info_req *req = (struct l2cap_info_req *) data; 34300a708f8fSGustavo F. Padovan u16 type; 34310a708f8fSGustavo F. Padovan 34320a708f8fSGustavo F. Padovan type = __le16_to_cpu(req->type); 34330a708f8fSGustavo F. Padovan 34340a708f8fSGustavo F. Padovan BT_DBG("type 0x%4.4x", type); 34350a708f8fSGustavo F. Padovan 34360a708f8fSGustavo F. Padovan if (type == L2CAP_IT_FEAT_MASK) { 34370a708f8fSGustavo F. Padovan u8 buf[8]; 34380a708f8fSGustavo F. Padovan u32 feat_mask = l2cap_feat_mask; 34390a708f8fSGustavo F. Padovan struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf; 34400a708f8fSGustavo F. Padovan rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK); 34410a708f8fSGustavo F. Padovan rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); 34420a708f8fSGustavo F. Padovan if (!disable_ertm) 34430a708f8fSGustavo F. Padovan feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING 34440a708f8fSGustavo F. Padovan | L2CAP_FEAT_FCS; 3445a5fd6f30SAndrei Emeltchenko if (enable_hs) 34466327eb98SAndrei Emeltchenko feat_mask |= L2CAP_FEAT_EXT_FLOW 34476327eb98SAndrei Emeltchenko | L2CAP_FEAT_EXT_WINDOW; 3448a5fd6f30SAndrei Emeltchenko 34490a708f8fSGustavo F. Padovan put_unaligned_le32(feat_mask, rsp->data); 34500a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, cmd->ident, 34510a708f8fSGustavo F. Padovan L2CAP_INFO_RSP, sizeof(buf), buf); 34520a708f8fSGustavo F. Padovan } else if (type == L2CAP_IT_FIXED_CHAN) { 34530a708f8fSGustavo F. Padovan u8 buf[12]; 34540a708f8fSGustavo F. Padovan struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf; 345550a147cdSMat Martineau 345650a147cdSMat Martineau if (enable_hs) 345750a147cdSMat Martineau l2cap_fixed_chan[0] |= L2CAP_FC_A2MP; 345850a147cdSMat Martineau else 345950a147cdSMat Martineau l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP; 346050a147cdSMat Martineau 34610a708f8fSGustavo F. Padovan rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); 34620a708f8fSGustavo F. Padovan rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); 3463c6337ea6SAndrei Emeltchenko memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan)); 34640a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, cmd->ident, 34650a708f8fSGustavo F. Padovan L2CAP_INFO_RSP, sizeof(buf), buf); 34660a708f8fSGustavo F. Padovan } else { 34670a708f8fSGustavo F. Padovan struct l2cap_info_rsp rsp; 34680a708f8fSGustavo F. Padovan rsp.type = cpu_to_le16(type); 34690a708f8fSGustavo F. Padovan rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP); 34700a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, cmd->ident, 34710a708f8fSGustavo F. Padovan L2CAP_INFO_RSP, sizeof(rsp), &rsp); 34720a708f8fSGustavo F. Padovan } 34730a708f8fSGustavo F. Padovan 34740a708f8fSGustavo F. Padovan return 0; 34750a708f8fSGustavo F. Padovan } 34760a708f8fSGustavo F. Padovan 34770a708f8fSGustavo F. Padovan static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) 34780a708f8fSGustavo F. Padovan { 34790a708f8fSGustavo F. Padovan struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data; 34800a708f8fSGustavo F. Padovan u16 type, result; 34810a708f8fSGustavo F. Padovan 34820a708f8fSGustavo F. Padovan type = __le16_to_cpu(rsp->type); 34830a708f8fSGustavo F. Padovan result = __le16_to_cpu(rsp->result); 34840a708f8fSGustavo F. Padovan 34850a708f8fSGustavo F. Padovan BT_DBG("type 0x%4.4x result 0x%2.2x", type, result); 34860a708f8fSGustavo F. Padovan 3487e90165beSAndrei Emeltchenko /* L2CAP Info req/rsp are unbound to channels, add extra checks */ 3488e90165beSAndrei Emeltchenko if (cmd->ident != conn->info_ident || 3489e90165beSAndrei Emeltchenko conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) 3490e90165beSAndrei Emeltchenko return 0; 3491e90165beSAndrei Emeltchenko 349217cd3f37SUlisses Furquim cancel_delayed_work(&conn->info_timer); 34930a708f8fSGustavo F. Padovan 34940a708f8fSGustavo F. Padovan if (result != L2CAP_IR_SUCCESS) { 34950a708f8fSGustavo F. Padovan conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; 34960a708f8fSGustavo F. Padovan conn->info_ident = 0; 34970a708f8fSGustavo F. Padovan 34980a708f8fSGustavo F. Padovan l2cap_conn_start(conn); 34990a708f8fSGustavo F. Padovan 35000a708f8fSGustavo F. Padovan return 0; 35010a708f8fSGustavo F. Padovan } 35020a708f8fSGustavo F. Padovan 3503978c93b9SAndrei Emeltchenko switch (type) { 3504978c93b9SAndrei Emeltchenko case L2CAP_IT_FEAT_MASK: 35050a708f8fSGustavo F. Padovan conn->feat_mask = get_unaligned_le32(rsp->data); 35060a708f8fSGustavo F. Padovan 35070a708f8fSGustavo F. Padovan if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) { 35080a708f8fSGustavo F. Padovan struct l2cap_info_req req; 35090a708f8fSGustavo F. Padovan req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); 35100a708f8fSGustavo F. Padovan 35110a708f8fSGustavo F. Padovan conn->info_ident = l2cap_get_ident(conn); 35120a708f8fSGustavo F. Padovan 35130a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, conn->info_ident, 35140a708f8fSGustavo F. Padovan L2CAP_INFO_REQ, sizeof(req), &req); 35150a708f8fSGustavo F. Padovan } else { 35160a708f8fSGustavo F. Padovan conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; 35170a708f8fSGustavo F. Padovan conn->info_ident = 0; 35180a708f8fSGustavo F. Padovan 35190a708f8fSGustavo F. Padovan l2cap_conn_start(conn); 35200a708f8fSGustavo F. Padovan } 3521978c93b9SAndrei Emeltchenko break; 3522978c93b9SAndrei Emeltchenko 3523978c93b9SAndrei Emeltchenko case L2CAP_IT_FIXED_CHAN: 3524978c93b9SAndrei Emeltchenko conn->fixed_chan_mask = rsp->data[0]; 35250a708f8fSGustavo F. Padovan conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE; 35260a708f8fSGustavo F. Padovan conn->info_ident = 0; 35270a708f8fSGustavo F. Padovan 35280a708f8fSGustavo F. Padovan l2cap_conn_start(conn); 3529978c93b9SAndrei Emeltchenko break; 35300a708f8fSGustavo F. Padovan } 35310a708f8fSGustavo F. Padovan 35320a708f8fSGustavo F. Padovan return 0; 35330a708f8fSGustavo F. Padovan } 35340a708f8fSGustavo F. Padovan 3535f94ff6ffSMat Martineau static inline int l2cap_create_channel_req(struct l2cap_conn *conn, 3536f94ff6ffSMat Martineau struct l2cap_cmd_hdr *cmd, u16 cmd_len, 3537f94ff6ffSMat Martineau void *data) 3538f94ff6ffSMat Martineau { 3539f94ff6ffSMat Martineau struct l2cap_create_chan_req *req = data; 3540f94ff6ffSMat Martineau struct l2cap_create_chan_rsp rsp; 3541f94ff6ffSMat Martineau u16 psm, scid; 3542f94ff6ffSMat Martineau 3543f94ff6ffSMat Martineau if (cmd_len != sizeof(*req)) 3544f94ff6ffSMat Martineau return -EPROTO; 3545f94ff6ffSMat Martineau 3546f94ff6ffSMat Martineau if (!enable_hs) 3547f94ff6ffSMat Martineau return -EINVAL; 3548f94ff6ffSMat Martineau 3549f94ff6ffSMat Martineau psm = le16_to_cpu(req->psm); 3550f94ff6ffSMat Martineau scid = le16_to_cpu(req->scid); 3551f94ff6ffSMat Martineau 3552f94ff6ffSMat Martineau BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id); 3553f94ff6ffSMat Martineau 3554f94ff6ffSMat Martineau /* Placeholder: Always reject */ 3555f94ff6ffSMat Martineau rsp.dcid = 0; 3556f94ff6ffSMat Martineau rsp.scid = cpu_to_le16(scid); 35578ce0c498SAndrei Emeltchenko rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM); 35588ce0c498SAndrei Emeltchenko rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); 3559f94ff6ffSMat Martineau 3560f94ff6ffSMat Martineau l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP, 3561f94ff6ffSMat Martineau sizeof(rsp), &rsp); 3562f94ff6ffSMat Martineau 3563f94ff6ffSMat Martineau return 0; 3564f94ff6ffSMat Martineau } 3565f94ff6ffSMat Martineau 3566f94ff6ffSMat Martineau static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn, 3567f94ff6ffSMat Martineau struct l2cap_cmd_hdr *cmd, void *data) 3568f94ff6ffSMat Martineau { 3569f94ff6ffSMat Martineau BT_DBG("conn %p", conn); 3570f94ff6ffSMat Martineau 3571f94ff6ffSMat Martineau return l2cap_connect_rsp(conn, cmd, data); 3572f94ff6ffSMat Martineau } 3573f94ff6ffSMat Martineau 35748d5a04a1SMat Martineau static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident, 35758d5a04a1SMat Martineau u16 icid, u16 result) 35768d5a04a1SMat Martineau { 35778d5a04a1SMat Martineau struct l2cap_move_chan_rsp rsp; 35788d5a04a1SMat Martineau 35798d5a04a1SMat Martineau BT_DBG("icid %d, result %d", icid, result); 35808d5a04a1SMat Martineau 35818d5a04a1SMat Martineau rsp.icid = cpu_to_le16(icid); 35828d5a04a1SMat Martineau rsp.result = cpu_to_le16(result); 35838d5a04a1SMat Martineau 35848d5a04a1SMat Martineau l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp); 35858d5a04a1SMat Martineau } 35868d5a04a1SMat Martineau 35878d5a04a1SMat Martineau static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn, 35888d5a04a1SMat Martineau struct l2cap_chan *chan, u16 icid, u16 result) 35898d5a04a1SMat Martineau { 35908d5a04a1SMat Martineau struct l2cap_move_chan_cfm cfm; 35918d5a04a1SMat Martineau u8 ident; 35928d5a04a1SMat Martineau 35938d5a04a1SMat Martineau BT_DBG("icid %d, result %d", icid, result); 35948d5a04a1SMat Martineau 35958d5a04a1SMat Martineau ident = l2cap_get_ident(conn); 35968d5a04a1SMat Martineau if (chan) 35978d5a04a1SMat Martineau chan->ident = ident; 35988d5a04a1SMat Martineau 35998d5a04a1SMat Martineau cfm.icid = cpu_to_le16(icid); 36008d5a04a1SMat Martineau cfm.result = cpu_to_le16(result); 36018d5a04a1SMat Martineau 36028d5a04a1SMat Martineau l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm); 36038d5a04a1SMat Martineau } 36048d5a04a1SMat Martineau 36058d5a04a1SMat Martineau static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, 36068d5a04a1SMat Martineau u16 icid) 36078d5a04a1SMat Martineau { 36088d5a04a1SMat Martineau struct l2cap_move_chan_cfm_rsp rsp; 36098d5a04a1SMat Martineau 36108d5a04a1SMat Martineau BT_DBG("icid %d", icid); 36118d5a04a1SMat Martineau 36128d5a04a1SMat Martineau rsp.icid = cpu_to_le16(icid); 36138d5a04a1SMat Martineau l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp); 36148d5a04a1SMat Martineau } 36158d5a04a1SMat Martineau 36168d5a04a1SMat Martineau static inline int l2cap_move_channel_req(struct l2cap_conn *conn, 36178d5a04a1SMat Martineau struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) 36188d5a04a1SMat Martineau { 36198d5a04a1SMat Martineau struct l2cap_move_chan_req *req = data; 36208d5a04a1SMat Martineau u16 icid = 0; 36218d5a04a1SMat Martineau u16 result = L2CAP_MR_NOT_ALLOWED; 36228d5a04a1SMat Martineau 36238d5a04a1SMat Martineau if (cmd_len != sizeof(*req)) 36248d5a04a1SMat Martineau return -EPROTO; 36258d5a04a1SMat Martineau 36268d5a04a1SMat Martineau icid = le16_to_cpu(req->icid); 36278d5a04a1SMat Martineau 36288d5a04a1SMat Martineau BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id); 36298d5a04a1SMat Martineau 36308d5a04a1SMat Martineau if (!enable_hs) 36318d5a04a1SMat Martineau return -EINVAL; 36328d5a04a1SMat Martineau 36338d5a04a1SMat Martineau /* Placeholder: Always refuse */ 36348d5a04a1SMat Martineau l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result); 36358d5a04a1SMat Martineau 36368d5a04a1SMat Martineau return 0; 36378d5a04a1SMat Martineau } 36388d5a04a1SMat Martineau 36398d5a04a1SMat Martineau static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, 36408d5a04a1SMat Martineau struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) 36418d5a04a1SMat Martineau { 36428d5a04a1SMat Martineau struct l2cap_move_chan_rsp *rsp = data; 36438d5a04a1SMat Martineau u16 icid, result; 36448d5a04a1SMat Martineau 36458d5a04a1SMat Martineau if (cmd_len != sizeof(*rsp)) 36468d5a04a1SMat Martineau return -EPROTO; 36478d5a04a1SMat Martineau 36488d5a04a1SMat Martineau icid = le16_to_cpu(rsp->icid); 36498d5a04a1SMat Martineau result = le16_to_cpu(rsp->result); 36508d5a04a1SMat Martineau 36518d5a04a1SMat Martineau BT_DBG("icid %d, result %d", icid, result); 36528d5a04a1SMat Martineau 36538d5a04a1SMat Martineau /* Placeholder: Always unconfirmed */ 36548d5a04a1SMat Martineau l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED); 36558d5a04a1SMat Martineau 36568d5a04a1SMat Martineau return 0; 36578d5a04a1SMat Martineau } 36588d5a04a1SMat Martineau 36598d5a04a1SMat Martineau static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, 36608d5a04a1SMat Martineau struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) 36618d5a04a1SMat Martineau { 36628d5a04a1SMat Martineau struct l2cap_move_chan_cfm *cfm = data; 36638d5a04a1SMat Martineau u16 icid, result; 36648d5a04a1SMat Martineau 36658d5a04a1SMat Martineau if (cmd_len != sizeof(*cfm)) 36668d5a04a1SMat Martineau return -EPROTO; 36678d5a04a1SMat Martineau 36688d5a04a1SMat Martineau icid = le16_to_cpu(cfm->icid); 36698d5a04a1SMat Martineau result = le16_to_cpu(cfm->result); 36708d5a04a1SMat Martineau 36718d5a04a1SMat Martineau BT_DBG("icid %d, result %d", icid, result); 36728d5a04a1SMat Martineau 36738d5a04a1SMat Martineau l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); 36748d5a04a1SMat Martineau 36758d5a04a1SMat Martineau return 0; 36768d5a04a1SMat Martineau } 36778d5a04a1SMat Martineau 36788d5a04a1SMat Martineau static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, 36798d5a04a1SMat Martineau struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) 36808d5a04a1SMat Martineau { 36818d5a04a1SMat Martineau struct l2cap_move_chan_cfm_rsp *rsp = data; 36828d5a04a1SMat Martineau u16 icid; 36838d5a04a1SMat Martineau 36848d5a04a1SMat Martineau if (cmd_len != sizeof(*rsp)) 36858d5a04a1SMat Martineau return -EPROTO; 36868d5a04a1SMat Martineau 36878d5a04a1SMat Martineau icid = le16_to_cpu(rsp->icid); 36888d5a04a1SMat Martineau 36898d5a04a1SMat Martineau BT_DBG("icid %d", icid); 36908d5a04a1SMat Martineau 36918d5a04a1SMat Martineau return 0; 36928d5a04a1SMat Martineau } 36938d5a04a1SMat Martineau 3694e2174ca4SGustavo F. Padovan static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency, 3695de73115aSClaudio Takahasi u16 to_multiplier) 3696de73115aSClaudio Takahasi { 3697de73115aSClaudio Takahasi u16 max_latency; 3698de73115aSClaudio Takahasi 3699de73115aSClaudio Takahasi if (min > max || min < 6 || max > 3200) 3700de73115aSClaudio Takahasi return -EINVAL; 3701de73115aSClaudio Takahasi 3702de73115aSClaudio Takahasi if (to_multiplier < 10 || to_multiplier > 3200) 3703de73115aSClaudio Takahasi return -EINVAL; 3704de73115aSClaudio Takahasi 3705de73115aSClaudio Takahasi if (max >= to_multiplier * 8) 3706de73115aSClaudio Takahasi return -EINVAL; 3707de73115aSClaudio Takahasi 3708de73115aSClaudio Takahasi max_latency = (to_multiplier * 8 / max) - 1; 3709de73115aSClaudio Takahasi if (latency > 499 || latency > max_latency) 3710de73115aSClaudio Takahasi return -EINVAL; 3711de73115aSClaudio Takahasi 3712de73115aSClaudio Takahasi return 0; 3713de73115aSClaudio Takahasi } 3714de73115aSClaudio Takahasi 3715de73115aSClaudio Takahasi static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, 3716de73115aSClaudio Takahasi struct l2cap_cmd_hdr *cmd, u8 *data) 3717de73115aSClaudio Takahasi { 3718de73115aSClaudio Takahasi struct hci_conn *hcon = conn->hcon; 3719de73115aSClaudio Takahasi struct l2cap_conn_param_update_req *req; 3720de73115aSClaudio Takahasi struct l2cap_conn_param_update_rsp rsp; 3721de73115aSClaudio Takahasi u16 min, max, latency, to_multiplier, cmd_len; 37222ce603ebSClaudio Takahasi int err; 3723de73115aSClaudio Takahasi 3724de73115aSClaudio Takahasi if (!(hcon->link_mode & HCI_LM_MASTER)) 3725de73115aSClaudio Takahasi return -EINVAL; 3726de73115aSClaudio Takahasi 3727de73115aSClaudio Takahasi cmd_len = __le16_to_cpu(cmd->len); 3728de73115aSClaudio Takahasi if (cmd_len != sizeof(struct l2cap_conn_param_update_req)) 3729de73115aSClaudio Takahasi return -EPROTO; 3730de73115aSClaudio Takahasi 3731de73115aSClaudio Takahasi req = (struct l2cap_conn_param_update_req *) data; 3732de73115aSClaudio Takahasi min = __le16_to_cpu(req->min); 3733de73115aSClaudio Takahasi max = __le16_to_cpu(req->max); 3734de73115aSClaudio Takahasi latency = __le16_to_cpu(req->latency); 3735de73115aSClaudio Takahasi to_multiplier = __le16_to_cpu(req->to_multiplier); 3736de73115aSClaudio Takahasi 3737de73115aSClaudio Takahasi BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x", 3738de73115aSClaudio Takahasi min, max, latency, to_multiplier); 3739de73115aSClaudio Takahasi 3740de73115aSClaudio Takahasi memset(&rsp, 0, sizeof(rsp)); 37412ce603ebSClaudio Takahasi 37422ce603ebSClaudio Takahasi err = l2cap_check_conn_param(min, max, latency, to_multiplier); 37432ce603ebSClaudio Takahasi if (err) 3744de73115aSClaudio Takahasi rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); 3745de73115aSClaudio Takahasi else 3746de73115aSClaudio Takahasi rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED); 3747de73115aSClaudio Takahasi 3748de73115aSClaudio Takahasi l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP, 3749de73115aSClaudio Takahasi sizeof(rsp), &rsp); 3750de73115aSClaudio Takahasi 37512ce603ebSClaudio Takahasi if (!err) 37522ce603ebSClaudio Takahasi hci_le_conn_update(hcon, min, max, latency, to_multiplier); 37532ce603ebSClaudio Takahasi 3754de73115aSClaudio Takahasi return 0; 3755de73115aSClaudio Takahasi } 3756de73115aSClaudio Takahasi 37573300d9a9SClaudio Takahasi static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn, 37583300d9a9SClaudio Takahasi struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) 37593300d9a9SClaudio Takahasi { 37603300d9a9SClaudio Takahasi int err = 0; 37613300d9a9SClaudio Takahasi 37623300d9a9SClaudio Takahasi switch (cmd->code) { 37633300d9a9SClaudio Takahasi case L2CAP_COMMAND_REJ: 37643300d9a9SClaudio Takahasi l2cap_command_rej(conn, cmd, data); 37653300d9a9SClaudio Takahasi break; 37663300d9a9SClaudio Takahasi 37673300d9a9SClaudio Takahasi case L2CAP_CONN_REQ: 37683300d9a9SClaudio Takahasi err = l2cap_connect_req(conn, cmd, data); 37693300d9a9SClaudio Takahasi break; 37703300d9a9SClaudio Takahasi 37713300d9a9SClaudio Takahasi case L2CAP_CONN_RSP: 37723300d9a9SClaudio Takahasi err = l2cap_connect_rsp(conn, cmd, data); 37733300d9a9SClaudio Takahasi break; 37743300d9a9SClaudio Takahasi 37753300d9a9SClaudio Takahasi case L2CAP_CONF_REQ: 37763300d9a9SClaudio Takahasi err = l2cap_config_req(conn, cmd, cmd_len, data); 37773300d9a9SClaudio Takahasi break; 37783300d9a9SClaudio Takahasi 37793300d9a9SClaudio Takahasi case L2CAP_CONF_RSP: 37803300d9a9SClaudio Takahasi err = l2cap_config_rsp(conn, cmd, data); 37813300d9a9SClaudio Takahasi break; 37823300d9a9SClaudio Takahasi 37833300d9a9SClaudio Takahasi case L2CAP_DISCONN_REQ: 37843300d9a9SClaudio Takahasi err = l2cap_disconnect_req(conn, cmd, data); 37853300d9a9SClaudio Takahasi break; 37863300d9a9SClaudio Takahasi 37873300d9a9SClaudio Takahasi case L2CAP_DISCONN_RSP: 37883300d9a9SClaudio Takahasi err = l2cap_disconnect_rsp(conn, cmd, data); 37893300d9a9SClaudio Takahasi break; 37903300d9a9SClaudio Takahasi 37913300d9a9SClaudio Takahasi case L2CAP_ECHO_REQ: 37923300d9a9SClaudio Takahasi l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data); 37933300d9a9SClaudio Takahasi break; 37943300d9a9SClaudio Takahasi 37953300d9a9SClaudio Takahasi case L2CAP_ECHO_RSP: 37963300d9a9SClaudio Takahasi break; 37973300d9a9SClaudio Takahasi 37983300d9a9SClaudio Takahasi case L2CAP_INFO_REQ: 37993300d9a9SClaudio Takahasi err = l2cap_information_req(conn, cmd, data); 38003300d9a9SClaudio Takahasi break; 38013300d9a9SClaudio Takahasi 38023300d9a9SClaudio Takahasi case L2CAP_INFO_RSP: 38033300d9a9SClaudio Takahasi err = l2cap_information_rsp(conn, cmd, data); 38043300d9a9SClaudio Takahasi break; 38053300d9a9SClaudio Takahasi 3806f94ff6ffSMat Martineau case L2CAP_CREATE_CHAN_REQ: 3807f94ff6ffSMat Martineau err = l2cap_create_channel_req(conn, cmd, cmd_len, data); 3808f94ff6ffSMat Martineau break; 3809f94ff6ffSMat Martineau 3810f94ff6ffSMat Martineau case L2CAP_CREATE_CHAN_RSP: 3811f94ff6ffSMat Martineau err = l2cap_create_channel_rsp(conn, cmd, data); 3812f94ff6ffSMat Martineau break; 3813f94ff6ffSMat Martineau 38148d5a04a1SMat Martineau case L2CAP_MOVE_CHAN_REQ: 38158d5a04a1SMat Martineau err = l2cap_move_channel_req(conn, cmd, cmd_len, data); 38168d5a04a1SMat Martineau break; 38178d5a04a1SMat Martineau 38188d5a04a1SMat Martineau case L2CAP_MOVE_CHAN_RSP: 38198d5a04a1SMat Martineau err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data); 38208d5a04a1SMat Martineau break; 38218d5a04a1SMat Martineau 38228d5a04a1SMat Martineau case L2CAP_MOVE_CHAN_CFM: 38238d5a04a1SMat Martineau err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data); 38248d5a04a1SMat Martineau break; 38258d5a04a1SMat Martineau 38268d5a04a1SMat Martineau case L2CAP_MOVE_CHAN_CFM_RSP: 38278d5a04a1SMat Martineau err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data); 38288d5a04a1SMat Martineau break; 38298d5a04a1SMat Martineau 38303300d9a9SClaudio Takahasi default: 38313300d9a9SClaudio Takahasi BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code); 38323300d9a9SClaudio Takahasi err = -EINVAL; 38333300d9a9SClaudio Takahasi break; 38343300d9a9SClaudio Takahasi } 38353300d9a9SClaudio Takahasi 38363300d9a9SClaudio Takahasi return err; 38373300d9a9SClaudio Takahasi } 38383300d9a9SClaudio Takahasi 38393300d9a9SClaudio Takahasi static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn, 38403300d9a9SClaudio Takahasi struct l2cap_cmd_hdr *cmd, u8 *data) 38413300d9a9SClaudio Takahasi { 38423300d9a9SClaudio Takahasi switch (cmd->code) { 38433300d9a9SClaudio Takahasi case L2CAP_COMMAND_REJ: 38443300d9a9SClaudio Takahasi return 0; 38453300d9a9SClaudio Takahasi 38463300d9a9SClaudio Takahasi case L2CAP_CONN_PARAM_UPDATE_REQ: 3847de73115aSClaudio Takahasi return l2cap_conn_param_update_req(conn, cmd, data); 38483300d9a9SClaudio Takahasi 38493300d9a9SClaudio Takahasi case L2CAP_CONN_PARAM_UPDATE_RSP: 38503300d9a9SClaudio Takahasi return 0; 38513300d9a9SClaudio Takahasi 38523300d9a9SClaudio Takahasi default: 38533300d9a9SClaudio Takahasi BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code); 38543300d9a9SClaudio Takahasi return -EINVAL; 38553300d9a9SClaudio Takahasi } 38563300d9a9SClaudio Takahasi } 38573300d9a9SClaudio Takahasi 38583300d9a9SClaudio Takahasi static inline void l2cap_sig_channel(struct l2cap_conn *conn, 38593300d9a9SClaudio Takahasi struct sk_buff *skb) 38600a708f8fSGustavo F. Padovan { 38610a708f8fSGustavo F. Padovan u8 *data = skb->data; 38620a708f8fSGustavo F. Padovan int len = skb->len; 38630a708f8fSGustavo F. Padovan struct l2cap_cmd_hdr cmd; 38643300d9a9SClaudio Takahasi int err; 38650a708f8fSGustavo F. Padovan 38660a708f8fSGustavo F. Padovan l2cap_raw_recv(conn, skb); 38670a708f8fSGustavo F. Padovan 38680a708f8fSGustavo F. Padovan while (len >= L2CAP_CMD_HDR_SIZE) { 38690a708f8fSGustavo F. Padovan u16 cmd_len; 38700a708f8fSGustavo F. Padovan memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE); 38710a708f8fSGustavo F. Padovan data += L2CAP_CMD_HDR_SIZE; 38720a708f8fSGustavo F. Padovan len -= L2CAP_CMD_HDR_SIZE; 38730a708f8fSGustavo F. Padovan 38740a708f8fSGustavo F. Padovan cmd_len = le16_to_cpu(cmd.len); 38750a708f8fSGustavo F. Padovan 38760a708f8fSGustavo F. Padovan BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len, cmd.ident); 38770a708f8fSGustavo F. Padovan 38780a708f8fSGustavo F. Padovan if (cmd_len > len || !cmd.ident) { 38790a708f8fSGustavo F. Padovan BT_DBG("corrupted command"); 38800a708f8fSGustavo F. Padovan break; 38810a708f8fSGustavo F. Padovan } 38820a708f8fSGustavo F. Padovan 38833300d9a9SClaudio Takahasi if (conn->hcon->type == LE_LINK) 38843300d9a9SClaudio Takahasi err = l2cap_le_sig_cmd(conn, &cmd, data); 38853300d9a9SClaudio Takahasi else 38863300d9a9SClaudio Takahasi err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data); 38870a708f8fSGustavo F. Padovan 38880a708f8fSGustavo F. Padovan if (err) { 3889e2fd318eSIlia Kolomisnky struct l2cap_cmd_rej_unk rej; 38902c6d1a2eSGustavo F. Padovan 38912c6d1a2eSGustavo F. Padovan BT_ERR("Wrong link type (%d)", err); 38920a708f8fSGustavo F. Padovan 38930a708f8fSGustavo F. Padovan /* FIXME: Map err to a valid reason */ 3894e2fd318eSIlia Kolomisnky rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD); 38950a708f8fSGustavo F. Padovan l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej); 38960a708f8fSGustavo F. Padovan } 38970a708f8fSGustavo F. Padovan 38980a708f8fSGustavo F. Padovan data += cmd_len; 38990a708f8fSGustavo F. Padovan len -= cmd_len; 39000a708f8fSGustavo F. Padovan } 39010a708f8fSGustavo F. Padovan 39020a708f8fSGustavo F. Padovan kfree_skb(skb); 39030a708f8fSGustavo F. Padovan } 39040a708f8fSGustavo F. Padovan 390547d1ec61SGustavo F. Padovan static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb) 39060a708f8fSGustavo F. Padovan { 39070a708f8fSGustavo F. Padovan u16 our_fcs, rcv_fcs; 3908e4ca6d98SAndrei Emeltchenko int hdr_size; 3909e4ca6d98SAndrei Emeltchenko 3910e4ca6d98SAndrei Emeltchenko if (test_bit(FLAG_EXT_CTRL, &chan->flags)) 3911e4ca6d98SAndrei Emeltchenko hdr_size = L2CAP_EXT_HDR_SIZE; 3912e4ca6d98SAndrei Emeltchenko else 3913e4ca6d98SAndrei Emeltchenko hdr_size = L2CAP_ENH_HDR_SIZE; 39140a708f8fSGustavo F. Padovan 391547d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_CRC16) { 391603a51213SAndrei Emeltchenko skb_trim(skb, skb->len - L2CAP_FCS_SIZE); 39170a708f8fSGustavo F. Padovan rcv_fcs = get_unaligned_le16(skb->data + skb->len); 39180a708f8fSGustavo F. Padovan our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size); 39190a708f8fSGustavo F. Padovan 39200a708f8fSGustavo F. Padovan if (our_fcs != rcv_fcs) 39210a708f8fSGustavo F. Padovan return -EBADMSG; 39220a708f8fSGustavo F. Padovan } 39230a708f8fSGustavo F. Padovan return 0; 39240a708f8fSGustavo F. Padovan } 39250a708f8fSGustavo F. Padovan 3926525cd185SGustavo F. Padovan static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) 39270a708f8fSGustavo F. Padovan { 392888843ab0SAndrei Emeltchenko u32 control = 0; 39290a708f8fSGustavo F. Padovan 39306a026610SGustavo F. Padovan chan->frames_sent = 0; 39310a708f8fSGustavo F. Padovan 39320b209faeSAndrei Emeltchenko control |= __set_reqseq(chan, chan->buffer_seq); 39330a708f8fSGustavo F. Padovan 3934e2ab4353SGustavo F. Padovan if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { 3935ab784b73SAndrei Emeltchenko control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); 3936525cd185SGustavo F. Padovan l2cap_send_sframe(chan, control); 3937e2ab4353SGustavo F. Padovan set_bit(CONN_RNR_SENT, &chan->conn_state); 39380a708f8fSGustavo F. Padovan } 39390a708f8fSGustavo F. Padovan 3940e2ab4353SGustavo F. Padovan if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) 3941525cd185SGustavo F. Padovan l2cap_retransmit_frames(chan); 39420a708f8fSGustavo F. Padovan 3943525cd185SGustavo F. Padovan l2cap_ertm_send(chan); 39440a708f8fSGustavo F. Padovan 3945e2ab4353SGustavo F. Padovan if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) && 39466a026610SGustavo F. Padovan chan->frames_sent == 0) { 3947ab784b73SAndrei Emeltchenko control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); 3948525cd185SGustavo F. Padovan l2cap_send_sframe(chan, control); 39490a708f8fSGustavo F. Padovan } 39500a708f8fSGustavo F. Padovan } 39510a708f8fSGustavo F. Padovan 3952fb45de7dSAndrei Emeltchenko static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar) 39530a708f8fSGustavo F. Padovan { 39540a708f8fSGustavo F. Padovan struct sk_buff *next_skb; 39550a708f8fSGustavo F. Padovan int tx_seq_offset, next_tx_seq_offset; 39560a708f8fSGustavo F. Padovan 39573ce3514fSMat Martineau bt_cb(skb)->control.txseq = tx_seq; 39583ce3514fSMat Martineau bt_cb(skb)->control.sar = sar; 39590a708f8fSGustavo F. Padovan 3960f1c6775bSGustavo F. Padovan next_skb = skb_peek(&chan->srej_q); 39610a708f8fSGustavo F. Padovan 3962836be934SAndrei Emeltchenko tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq); 39630a708f8fSGustavo F. Padovan 3964039d9572SSzymon Janc while (next_skb) { 39653ce3514fSMat Martineau if (bt_cb(next_skb)->control.txseq == tx_seq) 39660a708f8fSGustavo F. Padovan return -EINVAL; 39670a708f8fSGustavo F. Padovan 3968836be934SAndrei Emeltchenko next_tx_seq_offset = __seq_offset(chan, 39693ce3514fSMat Martineau bt_cb(next_skb)->control.txseq, chan->buffer_seq); 39700a708f8fSGustavo F. Padovan 39710a708f8fSGustavo F. Padovan if (next_tx_seq_offset > tx_seq_offset) { 3972f1c6775bSGustavo F. Padovan __skb_queue_before(&chan->srej_q, next_skb, skb); 39730a708f8fSGustavo F. Padovan return 0; 39740a708f8fSGustavo F. Padovan } 39750a708f8fSGustavo F. Padovan 3976f1c6775bSGustavo F. Padovan if (skb_queue_is_last(&chan->srej_q, next_skb)) 3977039d9572SSzymon Janc next_skb = NULL; 3978039d9572SSzymon Janc else 3979039d9572SSzymon Janc next_skb = skb_queue_next(&chan->srej_q, next_skb); 3980039d9572SSzymon Janc } 39810a708f8fSGustavo F. Padovan 3982f1c6775bSGustavo F. Padovan __skb_queue_tail(&chan->srej_q, skb); 39830a708f8fSGustavo F. Padovan 39840a708f8fSGustavo F. Padovan return 0; 39850a708f8fSGustavo F. Padovan } 39860a708f8fSGustavo F. Padovan 398784084a31SMat Martineau static void append_skb_frag(struct sk_buff *skb, 398884084a31SMat Martineau struct sk_buff *new_frag, struct sk_buff **last_frag) 39890a708f8fSGustavo F. Padovan { 399084084a31SMat Martineau /* skb->len reflects data in skb as well as all fragments 399184084a31SMat Martineau * skb->data_len reflects only data in fragments 399284084a31SMat Martineau */ 399384084a31SMat Martineau if (!skb_has_frag_list(skb)) 399484084a31SMat Martineau skb_shinfo(skb)->frag_list = new_frag; 399584084a31SMat Martineau 399684084a31SMat Martineau new_frag->next = NULL; 399784084a31SMat Martineau 399884084a31SMat Martineau (*last_frag)->next = new_frag; 399984084a31SMat Martineau *last_frag = new_frag; 400084084a31SMat Martineau 400184084a31SMat Martineau skb->len += new_frag->len; 400284084a31SMat Martineau skb->data_len += new_frag->len; 400384084a31SMat Martineau skb->truesize += new_frag->truesize; 400484084a31SMat Martineau } 400584084a31SMat Martineau 400688843ab0SAndrei Emeltchenko static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control) 400784084a31SMat Martineau { 400884084a31SMat Martineau int err = -EINVAL; 40090a708f8fSGustavo F. Padovan 40107e0ef6eeSAndrei Emeltchenko switch (__get_ctrl_sar(chan, control)) { 40117e0ef6eeSAndrei Emeltchenko case L2CAP_SAR_UNSEGMENTED: 401284084a31SMat Martineau if (chan->sdu) 401384084a31SMat Martineau break; 40140a708f8fSGustavo F. Padovan 401584084a31SMat Martineau err = chan->ops->recv(chan->data, skb); 401684084a31SMat Martineau break; 40170a708f8fSGustavo F. Padovan 40187e0ef6eeSAndrei Emeltchenko case L2CAP_SAR_START: 401984084a31SMat Martineau if (chan->sdu) 402084084a31SMat Martineau break; 40210a708f8fSGustavo F. Padovan 40226f61fd47SGustavo F. Padovan chan->sdu_len = get_unaligned_le16(skb->data); 402303a51213SAndrei Emeltchenko skb_pull(skb, L2CAP_SDULEN_SIZE); 40240a708f8fSGustavo F. Padovan 402584084a31SMat Martineau if (chan->sdu_len > chan->imtu) { 402684084a31SMat Martineau err = -EMSGSIZE; 402784084a31SMat Martineau break; 402884084a31SMat Martineau } 40290a708f8fSGustavo F. Padovan 403084084a31SMat Martineau if (skb->len >= chan->sdu_len) 403184084a31SMat Martineau break; 403284084a31SMat Martineau 403384084a31SMat Martineau chan->sdu = skb; 403484084a31SMat Martineau chan->sdu_last_frag = skb; 403584084a31SMat Martineau 403684084a31SMat Martineau skb = NULL; 403784084a31SMat Martineau err = 0; 40380a708f8fSGustavo F. Padovan break; 40390a708f8fSGustavo F. Padovan 40407e0ef6eeSAndrei Emeltchenko case L2CAP_SAR_CONTINUE: 40416f61fd47SGustavo F. Padovan if (!chan->sdu) 404284084a31SMat Martineau break; 40430a708f8fSGustavo F. Padovan 404484084a31SMat Martineau append_skb_frag(chan->sdu, skb, 404584084a31SMat Martineau &chan->sdu_last_frag); 404684084a31SMat Martineau skb = NULL; 40470a708f8fSGustavo F. Padovan 404884084a31SMat Martineau if (chan->sdu->len >= chan->sdu_len) 404984084a31SMat Martineau break; 40500a708f8fSGustavo F. Padovan 405184084a31SMat Martineau err = 0; 40520a708f8fSGustavo F. Padovan break; 40530a708f8fSGustavo F. Padovan 40547e0ef6eeSAndrei Emeltchenko case L2CAP_SAR_END: 40556f61fd47SGustavo F. Padovan if (!chan->sdu) 405684084a31SMat Martineau break; 40570a708f8fSGustavo F. Padovan 405884084a31SMat Martineau append_skb_frag(chan->sdu, skb, 405984084a31SMat Martineau &chan->sdu_last_frag); 406084084a31SMat Martineau skb = NULL; 40610a708f8fSGustavo F. Padovan 406284084a31SMat Martineau if (chan->sdu->len != chan->sdu_len) 406384084a31SMat Martineau break; 40640a708f8fSGustavo F. Padovan 406584084a31SMat Martineau err = chan->ops->recv(chan->data, chan->sdu); 40660a708f8fSGustavo F. Padovan 406784084a31SMat Martineau if (!err) { 406884084a31SMat Martineau /* Reassembly complete */ 406984084a31SMat Martineau chan->sdu = NULL; 407084084a31SMat Martineau chan->sdu_last_frag = NULL; 407184084a31SMat Martineau chan->sdu_len = 0; 40720a708f8fSGustavo F. Padovan } 40730a708f8fSGustavo F. Padovan break; 40740a708f8fSGustavo F. Padovan } 40750a708f8fSGustavo F. Padovan 407684084a31SMat Martineau if (err) { 40770a708f8fSGustavo F. Padovan kfree_skb(skb); 40786f61fd47SGustavo F. Padovan kfree_skb(chan->sdu); 40796f61fd47SGustavo F. Padovan chan->sdu = NULL; 408084084a31SMat Martineau chan->sdu_last_frag = NULL; 408184084a31SMat Martineau chan->sdu_len = 0; 408284084a31SMat Martineau } 40830a708f8fSGustavo F. Padovan 408484084a31SMat Martineau return err; 40850a708f8fSGustavo F. Padovan } 40860a708f8fSGustavo F. Padovan 408726f880d2SMat Martineau static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) 40880a708f8fSGustavo F. Padovan { 408926f880d2SMat Martineau BT_DBG("chan %p, Enter local busy", chan); 409026f880d2SMat Martineau 409126f880d2SMat Martineau set_bit(CONN_LOCAL_BUSY, &chan->conn_state); 40923c588192SMat Martineau l2cap_seq_list_clear(&chan->srej_list); 409326f880d2SMat Martineau 409477f918bcSSzymon Janc __set_ack_timer(chan); 40950a708f8fSGustavo F. Padovan } 40960a708f8fSGustavo F. Padovan 409726f880d2SMat Martineau static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan) 409826f880d2SMat Martineau { 409988843ab0SAndrei Emeltchenko u32 control; 41000a708f8fSGustavo F. Padovan 4101e2ab4353SGustavo F. Padovan if (!test_bit(CONN_RNR_SENT, &chan->conn_state)) 41020a708f8fSGustavo F. Padovan goto done; 41030a708f8fSGustavo F. Padovan 41040b209faeSAndrei Emeltchenko control = __set_reqseq(chan, chan->buffer_seq); 4105e3781735SAndrei Emeltchenko control |= __set_ctrl_poll(chan); 4106ab784b73SAndrei Emeltchenko control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); 4107525cd185SGustavo F. Padovan l2cap_send_sframe(chan, control); 41086a026610SGustavo F. Padovan chan->retry_count = 1; 41090a708f8fSGustavo F. Padovan 41101a09bcb9SGustavo F. Padovan __clear_retrans_timer(chan); 41111a09bcb9SGustavo F. Padovan __set_monitor_timer(chan); 41120a708f8fSGustavo F. Padovan 4113e2ab4353SGustavo F. Padovan set_bit(CONN_WAIT_F, &chan->conn_state); 41140a708f8fSGustavo F. Padovan 41150a708f8fSGustavo F. Padovan done: 4116e2ab4353SGustavo F. Padovan clear_bit(CONN_LOCAL_BUSY, &chan->conn_state); 4117e2ab4353SGustavo F. Padovan clear_bit(CONN_RNR_SENT, &chan->conn_state); 41180a708f8fSGustavo F. Padovan 411949208c9cSGustavo F. Padovan BT_DBG("chan %p, Exit local busy", chan); 41200a708f8fSGustavo F. Padovan } 41210a708f8fSGustavo F. Padovan 4122e328140fSMat Martineau void l2cap_chan_busy(struct l2cap_chan *chan, int busy) 41230a708f8fSGustavo F. Padovan { 4124e328140fSMat Martineau if (chan->mode == L2CAP_MODE_ERTM) { 4125e328140fSMat Martineau if (busy) 412626f880d2SMat Martineau l2cap_ertm_enter_local_busy(chan); 4127e328140fSMat Martineau else 4128e328140fSMat Martineau l2cap_ertm_exit_local_busy(chan); 41290a708f8fSGustavo F. Padovan } 41300a708f8fSGustavo F. Padovan } 41310a708f8fSGustavo F. Padovan 4132fb45de7dSAndrei Emeltchenko static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq) 41330a708f8fSGustavo F. Padovan { 41340a708f8fSGustavo F. Padovan struct sk_buff *skb; 413588843ab0SAndrei Emeltchenko u32 control; 41360a708f8fSGustavo F. Padovan 4137e328140fSMat Martineau while ((skb = skb_peek(&chan->srej_q)) && 4138e328140fSMat Martineau !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { 4139e328140fSMat Martineau int err; 4140e328140fSMat Martineau 41413ce3514fSMat Martineau if (bt_cb(skb)->control.txseq != tx_seq) 41420a708f8fSGustavo F. Padovan break; 41430a708f8fSGustavo F. Padovan 4144f1c6775bSGustavo F. Padovan skb = skb_dequeue(&chan->srej_q); 41453ce3514fSMat Martineau control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar); 414684084a31SMat Martineau err = l2cap_reassemble_sdu(chan, skb, control); 4147e328140fSMat Martineau 4148e328140fSMat Martineau if (err < 0) { 4149e328140fSMat Martineau l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); 4150e328140fSMat Martineau break; 4151e328140fSMat Martineau } 4152e328140fSMat Martineau 4153836be934SAndrei Emeltchenko chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej); 4154836be934SAndrei Emeltchenko tx_seq = __next_seq(chan, tx_seq); 41550a708f8fSGustavo F. Padovan } 41560a708f8fSGustavo F. Padovan } 41570a708f8fSGustavo F. Padovan 4158fb45de7dSAndrei Emeltchenko static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq) 41590a708f8fSGustavo F. Padovan { 41600a708f8fSGustavo F. Padovan struct srej_list *l, *tmp; 416188843ab0SAndrei Emeltchenko u32 control; 41620a708f8fSGustavo F. Padovan 416339d5a3eeSGustavo F. Padovan list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { 41640a708f8fSGustavo F. Padovan if (l->tx_seq == tx_seq) { 41650a708f8fSGustavo F. Padovan list_del(&l->list); 41660a708f8fSGustavo F. Padovan kfree(l); 41670a708f8fSGustavo F. Padovan return; 41680a708f8fSGustavo F. Padovan } 4169ab784b73SAndrei Emeltchenko control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); 41700b209faeSAndrei Emeltchenko control |= __set_reqseq(chan, l->tx_seq); 4171525cd185SGustavo F. Padovan l2cap_send_sframe(chan, control); 41720a708f8fSGustavo F. Padovan list_del(&l->list); 417339d5a3eeSGustavo F. Padovan list_add_tail(&l->list, &chan->srej_l); 41740a708f8fSGustavo F. Padovan } 41750a708f8fSGustavo F. Padovan } 41760a708f8fSGustavo F. Padovan 4177aef89f21SSzymon Janc static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq) 41780a708f8fSGustavo F. Padovan { 41790a708f8fSGustavo F. Padovan struct srej_list *new; 418088843ab0SAndrei Emeltchenko u32 control; 41810a708f8fSGustavo F. Padovan 418242e5c802SGustavo F. Padovan while (tx_seq != chan->expected_tx_seq) { 4183ab784b73SAndrei Emeltchenko control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); 41840b209faeSAndrei Emeltchenko control |= __set_reqseq(chan, chan->expected_tx_seq); 41853c588192SMat Martineau l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq); 4186525cd185SGustavo F. Padovan l2cap_send_sframe(chan, control); 41870a708f8fSGustavo F. Padovan 41880a708f8fSGustavo F. Padovan new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); 4189aef89f21SSzymon Janc if (!new) 4190aef89f21SSzymon Janc return -ENOMEM; 4191aef89f21SSzymon Janc 419242e5c802SGustavo F. Padovan new->tx_seq = chan->expected_tx_seq; 4193836be934SAndrei Emeltchenko 4194836be934SAndrei Emeltchenko chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq); 4195836be934SAndrei Emeltchenko 419639d5a3eeSGustavo F. Padovan list_add_tail(&new->list, &chan->srej_l); 41970a708f8fSGustavo F. Padovan } 4198836be934SAndrei Emeltchenko 4199836be934SAndrei Emeltchenko chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq); 4200aef89f21SSzymon Janc 4201aef89f21SSzymon Janc return 0; 42020a708f8fSGustavo F. Padovan } 42030a708f8fSGustavo F. Padovan 420488843ab0SAndrei Emeltchenko static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb) 42050a708f8fSGustavo F. Padovan { 4206fb45de7dSAndrei Emeltchenko u16 tx_seq = __get_txseq(chan, rx_control); 42070b209faeSAndrei Emeltchenko u16 req_seq = __get_reqseq(chan, rx_control); 42087e0ef6eeSAndrei Emeltchenko u8 sar = __get_ctrl_sar(chan, rx_control); 42090a708f8fSGustavo F. Padovan int tx_seq_offset, expected_tx_seq_offset; 421047d1ec61SGustavo F. Padovan int num_to_ack = (chan->tx_win/6) + 1; 42110a708f8fSGustavo F. Padovan int err = 0; 42120a708f8fSGustavo F. Padovan 421388843ab0SAndrei Emeltchenko BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len, 4214525cd185SGustavo F. Padovan tx_seq, rx_control); 42150a708f8fSGustavo F. Padovan 421603f6715dSAndrei Emeltchenko if (__is_ctrl_final(chan, rx_control) && 4217e2ab4353SGustavo F. Padovan test_bit(CONN_WAIT_F, &chan->conn_state)) { 42181a09bcb9SGustavo F. Padovan __clear_monitor_timer(chan); 42196a026610SGustavo F. Padovan if (chan->unacked_frames > 0) 42201a09bcb9SGustavo F. Padovan __set_retrans_timer(chan); 4221e2ab4353SGustavo F. Padovan clear_bit(CONN_WAIT_F, &chan->conn_state); 42220a708f8fSGustavo F. Padovan } 42230a708f8fSGustavo F. Padovan 422442e5c802SGustavo F. Padovan chan->expected_ack_seq = req_seq; 422542e5c802SGustavo F. Padovan l2cap_drop_acked_frames(chan); 42260a708f8fSGustavo F. Padovan 4227836be934SAndrei Emeltchenko tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq); 42280a708f8fSGustavo F. Padovan 42290a708f8fSGustavo F. Padovan /* invalid tx_seq */ 423047d1ec61SGustavo F. Padovan if (tx_seq_offset >= chan->tx_win) { 42318c1d787bSGustavo F. Padovan l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); 42320a708f8fSGustavo F. Padovan goto drop; 42330a708f8fSGustavo F. Padovan } 42340a708f8fSGustavo F. Padovan 423577f918bcSSzymon Janc if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { 423677f918bcSSzymon Janc if (!test_bit(CONN_RNR_SENT, &chan->conn_state)) 423777f918bcSSzymon Janc l2cap_send_ack(chan); 42380a708f8fSGustavo F. Padovan goto drop; 423977f918bcSSzymon Janc } 42400a708f8fSGustavo F. Padovan 424102f1b641SMat Martineau if (tx_seq == chan->expected_tx_seq) 424202f1b641SMat Martineau goto expected; 424302f1b641SMat Martineau 4244e2ab4353SGustavo F. Padovan if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { 42450a708f8fSGustavo F. Padovan struct srej_list *first; 42460a708f8fSGustavo F. Padovan 424739d5a3eeSGustavo F. Padovan first = list_first_entry(&chan->srej_l, 42480a708f8fSGustavo F. Padovan struct srej_list, list); 42490a708f8fSGustavo F. Padovan if (tx_seq == first->tx_seq) { 425042e5c802SGustavo F. Padovan l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); 4251525cd185SGustavo F. Padovan l2cap_check_srej_gap(chan, tx_seq); 42520a708f8fSGustavo F. Padovan 42530a708f8fSGustavo F. Padovan list_del(&first->list); 42540a708f8fSGustavo F. Padovan kfree(first); 42550a708f8fSGustavo F. Padovan 425639d5a3eeSGustavo F. Padovan if (list_empty(&chan->srej_l)) { 425742e5c802SGustavo F. Padovan chan->buffer_seq = chan->buffer_seq_srej; 4258e2ab4353SGustavo F. Padovan clear_bit(CONN_SREJ_SENT, &chan->conn_state); 4259525cd185SGustavo F. Padovan l2cap_send_ack(chan); 426049208c9cSGustavo F. Padovan BT_DBG("chan %p, Exit SREJ_SENT", chan); 42610a708f8fSGustavo F. Padovan } 42620a708f8fSGustavo F. Padovan } else { 42630a708f8fSGustavo F. Padovan struct srej_list *l; 42640a708f8fSGustavo F. Padovan 42650a708f8fSGustavo F. Padovan /* duplicated tx_seq */ 426642e5c802SGustavo F. Padovan if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0) 42670a708f8fSGustavo F. Padovan goto drop; 42680a708f8fSGustavo F. Padovan 426939d5a3eeSGustavo F. Padovan list_for_each_entry(l, &chan->srej_l, list) { 42700a708f8fSGustavo F. Padovan if (l->tx_seq == tx_seq) { 4271525cd185SGustavo F. Padovan l2cap_resend_srejframe(chan, tx_seq); 42720a708f8fSGustavo F. Padovan return 0; 42730a708f8fSGustavo F. Padovan } 42740a708f8fSGustavo F. Padovan } 4275aef89f21SSzymon Janc 4276aef89f21SSzymon Janc err = l2cap_send_srejframe(chan, tx_seq); 4277aef89f21SSzymon Janc if (err < 0) { 4278aef89f21SSzymon Janc l2cap_send_disconn_req(chan->conn, chan, -err); 4279aef89f21SSzymon Janc return err; 4280aef89f21SSzymon Janc } 42810a708f8fSGustavo F. Padovan } 42820a708f8fSGustavo F. Padovan } else { 4283836be934SAndrei Emeltchenko expected_tx_seq_offset = __seq_offset(chan, 4284836be934SAndrei Emeltchenko chan->expected_tx_seq, chan->buffer_seq); 42850a708f8fSGustavo F. Padovan 42860a708f8fSGustavo F. Padovan /* duplicated tx_seq */ 42870a708f8fSGustavo F. Padovan if (tx_seq_offset < expected_tx_seq_offset) 42880a708f8fSGustavo F. Padovan goto drop; 42890a708f8fSGustavo F. Padovan 4290e2ab4353SGustavo F. Padovan set_bit(CONN_SREJ_SENT, &chan->conn_state); 42910a708f8fSGustavo F. Padovan 429249208c9cSGustavo F. Padovan BT_DBG("chan %p, Enter SREJ", chan); 42930a708f8fSGustavo F. Padovan 429439d5a3eeSGustavo F. Padovan INIT_LIST_HEAD(&chan->srej_l); 429542e5c802SGustavo F. Padovan chan->buffer_seq_srej = chan->buffer_seq; 42960a708f8fSGustavo F. Padovan 4297f1c6775bSGustavo F. Padovan __skb_queue_head_init(&chan->srej_q); 429842e5c802SGustavo F. Padovan l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); 42990a708f8fSGustavo F. Padovan 43000ef3ef0fSSzymon Janc /* Set P-bit only if there are some I-frames to ack. */ 43010ef3ef0fSSzymon Janc if (__clear_ack_timer(chan)) 4302e2ab4353SGustavo F. Padovan set_bit(CONN_SEND_PBIT, &chan->conn_state); 43030a708f8fSGustavo F. Padovan 4304aef89f21SSzymon Janc err = l2cap_send_srejframe(chan, tx_seq); 4305aef89f21SSzymon Janc if (err < 0) { 4306aef89f21SSzymon Janc l2cap_send_disconn_req(chan->conn, chan, -err); 4307aef89f21SSzymon Janc return err; 4308aef89f21SSzymon Janc } 43090a708f8fSGustavo F. Padovan } 43100a708f8fSGustavo F. Padovan return 0; 43110a708f8fSGustavo F. Padovan 43120a708f8fSGustavo F. Padovan expected: 4313836be934SAndrei Emeltchenko chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq); 43140a708f8fSGustavo F. Padovan 4315e2ab4353SGustavo F. Padovan if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { 43163ce3514fSMat Martineau bt_cb(skb)->control.txseq = tx_seq; 43173ce3514fSMat Martineau bt_cb(skb)->control.sar = sar; 4318f1c6775bSGustavo F. Padovan __skb_queue_tail(&chan->srej_q, skb); 43190a708f8fSGustavo F. Padovan return 0; 43200a708f8fSGustavo F. Padovan } 43210a708f8fSGustavo F. Padovan 432284084a31SMat Martineau err = l2cap_reassemble_sdu(chan, skb, rx_control); 4323836be934SAndrei Emeltchenko chan->buffer_seq = __next_seq(chan, chan->buffer_seq); 4324836be934SAndrei Emeltchenko 4325e328140fSMat Martineau if (err < 0) { 4326e328140fSMat Martineau l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); 4327e328140fSMat Martineau return err; 4328e328140fSMat Martineau } 43290a708f8fSGustavo F. Padovan 433003f6715dSAndrei Emeltchenko if (__is_ctrl_final(chan, rx_control)) { 4331e2ab4353SGustavo F. Padovan if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state)) 4332525cd185SGustavo F. Padovan l2cap_retransmit_frames(chan); 43330a708f8fSGustavo F. Padovan } 43340a708f8fSGustavo F. Padovan 43350a708f8fSGustavo F. Padovan 43366a026610SGustavo F. Padovan chan->num_acked = (chan->num_acked + 1) % num_to_ack; 43376a026610SGustavo F. Padovan if (chan->num_acked == num_to_ack - 1) 4338525cd185SGustavo F. Padovan l2cap_send_ack(chan); 43394d611e4dSGustavo F. Padovan else 43404d611e4dSGustavo F. Padovan __set_ack_timer(chan); 43410a708f8fSGustavo F. Padovan 43420a708f8fSGustavo F. Padovan return 0; 43430a708f8fSGustavo F. Padovan 43440a708f8fSGustavo F. Padovan drop: 43450a708f8fSGustavo F. Padovan kfree_skb(skb); 43460a708f8fSGustavo F. Padovan return 0; 43470a708f8fSGustavo F. Padovan } 43480a708f8fSGustavo F. Padovan 434988843ab0SAndrei Emeltchenko static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control) 43500a708f8fSGustavo F. Padovan { 435188843ab0SAndrei Emeltchenko BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, 43520b209faeSAndrei Emeltchenko __get_reqseq(chan, rx_control), rx_control); 43530a708f8fSGustavo F. Padovan 43540b209faeSAndrei Emeltchenko chan->expected_ack_seq = __get_reqseq(chan, rx_control); 435542e5c802SGustavo F. Padovan l2cap_drop_acked_frames(chan); 43560a708f8fSGustavo F. Padovan 4357e3781735SAndrei Emeltchenko if (__is_ctrl_poll(chan, rx_control)) { 4358e2ab4353SGustavo F. Padovan set_bit(CONN_SEND_FBIT, &chan->conn_state); 4359e2ab4353SGustavo F. Padovan if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { 4360e2ab4353SGustavo F. Padovan if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) && 43616a026610SGustavo F. Padovan (chan->unacked_frames > 0)) 43621a09bcb9SGustavo F. Padovan __set_retrans_timer(chan); 43630a708f8fSGustavo F. Padovan 4364e2ab4353SGustavo F. Padovan clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); 4365525cd185SGustavo F. Padovan l2cap_send_srejtail(chan); 43660a708f8fSGustavo F. Padovan } else { 4367525cd185SGustavo F. Padovan l2cap_send_i_or_rr_or_rnr(chan); 43680a708f8fSGustavo F. Padovan } 43690a708f8fSGustavo F. Padovan 437003f6715dSAndrei Emeltchenko } else if (__is_ctrl_final(chan, rx_control)) { 4371e2ab4353SGustavo F. Padovan clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); 43720a708f8fSGustavo F. Padovan 4373e2ab4353SGustavo F. Padovan if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state)) 4374525cd185SGustavo F. Padovan l2cap_retransmit_frames(chan); 43750a708f8fSGustavo F. Padovan 43760a708f8fSGustavo F. Padovan } else { 4377e2ab4353SGustavo F. Padovan if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) && 43786a026610SGustavo F. Padovan (chan->unacked_frames > 0)) 43791a09bcb9SGustavo F. Padovan __set_retrans_timer(chan); 43800a708f8fSGustavo F. Padovan 4381e2ab4353SGustavo F. Padovan clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); 4382e2ab4353SGustavo F. Padovan if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) 4383525cd185SGustavo F. Padovan l2cap_send_ack(chan); 43840a708f8fSGustavo F. Padovan else 4385525cd185SGustavo F. Padovan l2cap_ertm_send(chan); 43860a708f8fSGustavo F. Padovan } 43870a708f8fSGustavo F. Padovan } 43880a708f8fSGustavo F. Padovan 438988843ab0SAndrei Emeltchenko static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control) 43900a708f8fSGustavo F. Padovan { 43910b209faeSAndrei Emeltchenko u16 tx_seq = __get_reqseq(chan, rx_control); 43920a708f8fSGustavo F. Padovan 439388843ab0SAndrei Emeltchenko BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control); 43940a708f8fSGustavo F. Padovan 4395e2ab4353SGustavo F. Padovan clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); 43960a708f8fSGustavo F. Padovan 439742e5c802SGustavo F. Padovan chan->expected_ack_seq = tx_seq; 439842e5c802SGustavo F. Padovan l2cap_drop_acked_frames(chan); 43990a708f8fSGustavo F. Padovan 440003f6715dSAndrei Emeltchenko if (__is_ctrl_final(chan, rx_control)) { 4401e2ab4353SGustavo F. Padovan if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state)) 4402525cd185SGustavo F. Padovan l2cap_retransmit_frames(chan); 44030a708f8fSGustavo F. Padovan } else { 4404525cd185SGustavo F. Padovan l2cap_retransmit_frames(chan); 44050a708f8fSGustavo F. Padovan 4406e2ab4353SGustavo F. Padovan if (test_bit(CONN_WAIT_F, &chan->conn_state)) 4407e2ab4353SGustavo F. Padovan set_bit(CONN_REJ_ACT, &chan->conn_state); 44080a708f8fSGustavo F. Padovan } 44090a708f8fSGustavo F. Padovan } 441088843ab0SAndrei Emeltchenko static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control) 44110a708f8fSGustavo F. Padovan { 44120b209faeSAndrei Emeltchenko u16 tx_seq = __get_reqseq(chan, rx_control); 44130a708f8fSGustavo F. Padovan 441488843ab0SAndrei Emeltchenko BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control); 44150a708f8fSGustavo F. Padovan 4416e2ab4353SGustavo F. Padovan clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); 44170a708f8fSGustavo F. Padovan 4418e3781735SAndrei Emeltchenko if (__is_ctrl_poll(chan, rx_control)) { 441942e5c802SGustavo F. Padovan chan->expected_ack_seq = tx_seq; 442042e5c802SGustavo F. Padovan l2cap_drop_acked_frames(chan); 44210a708f8fSGustavo F. Padovan 4422e2ab4353SGustavo F. Padovan set_bit(CONN_SEND_FBIT, &chan->conn_state); 4423525cd185SGustavo F. Padovan l2cap_retransmit_one_frame(chan, tx_seq); 44240a708f8fSGustavo F. Padovan 4425525cd185SGustavo F. Padovan l2cap_ertm_send(chan); 44260a708f8fSGustavo F. Padovan 4427e2ab4353SGustavo F. Padovan if (test_bit(CONN_WAIT_F, &chan->conn_state)) { 44286a026610SGustavo F. Padovan chan->srej_save_reqseq = tx_seq; 4429e2ab4353SGustavo F. Padovan set_bit(CONN_SREJ_ACT, &chan->conn_state); 44300a708f8fSGustavo F. Padovan } 443103f6715dSAndrei Emeltchenko } else if (__is_ctrl_final(chan, rx_control)) { 4432e2ab4353SGustavo F. Padovan if (test_bit(CONN_SREJ_ACT, &chan->conn_state) && 44336a026610SGustavo F. Padovan chan->srej_save_reqseq == tx_seq) 4434e2ab4353SGustavo F. Padovan clear_bit(CONN_SREJ_ACT, &chan->conn_state); 44350a708f8fSGustavo F. Padovan else 4436525cd185SGustavo F. Padovan l2cap_retransmit_one_frame(chan, tx_seq); 44370a708f8fSGustavo F. Padovan } else { 4438525cd185SGustavo F. Padovan l2cap_retransmit_one_frame(chan, tx_seq); 4439e2ab4353SGustavo F. Padovan if (test_bit(CONN_WAIT_F, &chan->conn_state)) { 44406a026610SGustavo F. Padovan chan->srej_save_reqseq = tx_seq; 4441e2ab4353SGustavo F. Padovan set_bit(CONN_SREJ_ACT, &chan->conn_state); 44420a708f8fSGustavo F. Padovan } 44430a708f8fSGustavo F. Padovan } 44440a708f8fSGustavo F. Padovan } 44450a708f8fSGustavo F. Padovan 444688843ab0SAndrei Emeltchenko static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control) 44470a708f8fSGustavo F. Padovan { 44480b209faeSAndrei Emeltchenko u16 tx_seq = __get_reqseq(chan, rx_control); 44490a708f8fSGustavo F. Padovan 445088843ab0SAndrei Emeltchenko BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control); 44510a708f8fSGustavo F. Padovan 4452e2ab4353SGustavo F. Padovan set_bit(CONN_REMOTE_BUSY, &chan->conn_state); 445342e5c802SGustavo F. Padovan chan->expected_ack_seq = tx_seq; 445442e5c802SGustavo F. Padovan l2cap_drop_acked_frames(chan); 44550a708f8fSGustavo F. Padovan 4456e3781735SAndrei Emeltchenko if (__is_ctrl_poll(chan, rx_control)) 4457e2ab4353SGustavo F. Padovan set_bit(CONN_SEND_FBIT, &chan->conn_state); 44580a708f8fSGustavo F. Padovan 4459e2ab4353SGustavo F. Padovan if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) { 44601a09bcb9SGustavo F. Padovan __clear_retrans_timer(chan); 4461e3781735SAndrei Emeltchenko if (__is_ctrl_poll(chan, rx_control)) 4462525cd185SGustavo F. Padovan l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL); 44630a708f8fSGustavo F. Padovan return; 44640a708f8fSGustavo F. Padovan } 44650a708f8fSGustavo F. Padovan 4466e3781735SAndrei Emeltchenko if (__is_ctrl_poll(chan, rx_control)) { 4467525cd185SGustavo F. Padovan l2cap_send_srejtail(chan); 4468ab784b73SAndrei Emeltchenko } else { 4469ab784b73SAndrei Emeltchenko rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR); 4470ab784b73SAndrei Emeltchenko l2cap_send_sframe(chan, rx_control); 4471ab784b73SAndrei Emeltchenko } 44720a708f8fSGustavo F. Padovan } 44730a708f8fSGustavo F. Padovan 447488843ab0SAndrei Emeltchenko static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb) 44750a708f8fSGustavo F. Padovan { 447688843ab0SAndrei Emeltchenko BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len); 44770a708f8fSGustavo F. Padovan 447803f6715dSAndrei Emeltchenko if (__is_ctrl_final(chan, rx_control) && 4479e2ab4353SGustavo F. Padovan test_bit(CONN_WAIT_F, &chan->conn_state)) { 44801a09bcb9SGustavo F. Padovan __clear_monitor_timer(chan); 44816a026610SGustavo F. Padovan if (chan->unacked_frames > 0) 44821a09bcb9SGustavo F. Padovan __set_retrans_timer(chan); 4483e2ab4353SGustavo F. Padovan clear_bit(CONN_WAIT_F, &chan->conn_state); 44840a708f8fSGustavo F. Padovan } 44850a708f8fSGustavo F. Padovan 4486ab784b73SAndrei Emeltchenko switch (__get_ctrl_super(chan, rx_control)) { 4487ab784b73SAndrei Emeltchenko case L2CAP_SUPER_RR: 4488525cd185SGustavo F. Padovan l2cap_data_channel_rrframe(chan, rx_control); 44890a708f8fSGustavo F. Padovan break; 44900a708f8fSGustavo F. Padovan 4491ab784b73SAndrei Emeltchenko case L2CAP_SUPER_REJ: 4492525cd185SGustavo F. Padovan l2cap_data_channel_rejframe(chan, rx_control); 44930a708f8fSGustavo F. Padovan break; 44940a708f8fSGustavo F. Padovan 4495ab784b73SAndrei Emeltchenko case L2CAP_SUPER_SREJ: 4496525cd185SGustavo F. Padovan l2cap_data_channel_srejframe(chan, rx_control); 44970a708f8fSGustavo F. Padovan break; 44980a708f8fSGustavo F. Padovan 4499ab784b73SAndrei Emeltchenko case L2CAP_SUPER_RNR: 4500525cd185SGustavo F. Padovan l2cap_data_channel_rnrframe(chan, rx_control); 45010a708f8fSGustavo F. Padovan break; 45020a708f8fSGustavo F. Padovan } 45030a708f8fSGustavo F. Padovan 45040a708f8fSGustavo F. Padovan kfree_skb(skb); 45050a708f8fSGustavo F. Padovan return 0; 45060a708f8fSGustavo F. Padovan } 45070a708f8fSGustavo F. Padovan 4508cad8f1d0SSzymon Janc static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) 45090a708f8fSGustavo F. Padovan { 451088843ab0SAndrei Emeltchenko u32 control; 45110b209faeSAndrei Emeltchenko u16 req_seq; 45120a708f8fSGustavo F. Padovan int len, next_tx_seq_offset, req_seq_offset; 45130a708f8fSGustavo F. Padovan 4514b76bbd66SMat Martineau __unpack_control(chan, skb); 4515b76bbd66SMat Martineau 451688843ab0SAndrei Emeltchenko control = __get_control(chan, skb->data); 451788843ab0SAndrei Emeltchenko skb_pull(skb, __ctrl_size(chan)); 45180a708f8fSGustavo F. Padovan len = skb->len; 45190a708f8fSGustavo F. Padovan 45200a708f8fSGustavo F. Padovan /* 45210a708f8fSGustavo F. Padovan * We can just drop the corrupted I-frame here. 45220a708f8fSGustavo F. Padovan * Receiver will miss it and start proper recovery 45230a708f8fSGustavo F. Padovan * procedures and ask retransmission. 45240a708f8fSGustavo F. Padovan */ 452547d1ec61SGustavo F. Padovan if (l2cap_check_fcs(chan, skb)) 45260a708f8fSGustavo F. Padovan goto drop; 45270a708f8fSGustavo F. Padovan 4528793c2f1cSAndrei Emeltchenko if (__is_sar_start(chan, control) && !__is_sframe(chan, control)) 452903a51213SAndrei Emeltchenko len -= L2CAP_SDULEN_SIZE; 45300a708f8fSGustavo F. Padovan 453147d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_CRC16) 453203a51213SAndrei Emeltchenko len -= L2CAP_FCS_SIZE; 45330a708f8fSGustavo F. Padovan 453447d1ec61SGustavo F. Padovan if (len > chan->mps) { 45358c1d787bSGustavo F. Padovan l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); 45360a708f8fSGustavo F. Padovan goto drop; 45370a708f8fSGustavo F. Padovan } 45380a708f8fSGustavo F. Padovan 45390b209faeSAndrei Emeltchenko req_seq = __get_reqseq(chan, control); 45400a708f8fSGustavo F. Padovan 4541836be934SAndrei Emeltchenko req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq); 4542836be934SAndrei Emeltchenko 4543836be934SAndrei Emeltchenko next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq, 4544836be934SAndrei Emeltchenko chan->expected_ack_seq); 45450a708f8fSGustavo F. Padovan 45460a708f8fSGustavo F. Padovan /* check for invalid req-seq */ 45470a708f8fSGustavo F. Padovan if (req_seq_offset > next_tx_seq_offset) { 45488c1d787bSGustavo F. Padovan l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); 45490a708f8fSGustavo F. Padovan goto drop; 45500a708f8fSGustavo F. Padovan } 45510a708f8fSGustavo F. Padovan 4552793c2f1cSAndrei Emeltchenko if (!__is_sframe(chan, control)) { 45530a708f8fSGustavo F. Padovan if (len < 0) { 45548c1d787bSGustavo F. Padovan l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); 45550a708f8fSGustavo F. Padovan goto drop; 45560a708f8fSGustavo F. Padovan } 45570a708f8fSGustavo F. Padovan 4558525cd185SGustavo F. Padovan l2cap_data_channel_iframe(chan, control, skb); 45590a708f8fSGustavo F. Padovan } else { 45600a708f8fSGustavo F. Padovan if (len != 0) { 45610a708f8fSGustavo F. Padovan BT_ERR("%d", len); 45628c1d787bSGustavo F. Padovan l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); 45630a708f8fSGustavo F. Padovan goto drop; 45640a708f8fSGustavo F. Padovan } 45650a708f8fSGustavo F. Padovan 4566525cd185SGustavo F. Padovan l2cap_data_channel_sframe(chan, control, skb); 45670a708f8fSGustavo F. Padovan } 45680a708f8fSGustavo F. Padovan 45690a708f8fSGustavo F. Padovan return 0; 45700a708f8fSGustavo F. Padovan 45710a708f8fSGustavo F. Padovan drop: 45720a708f8fSGustavo F. Padovan kfree_skb(skb); 45730a708f8fSGustavo F. Padovan return 0; 45740a708f8fSGustavo F. Padovan } 45750a708f8fSGustavo F. Padovan 45760a708f8fSGustavo F. Padovan static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) 45770a708f8fSGustavo F. Padovan { 457848454079SGustavo F. Padovan struct l2cap_chan *chan; 457988843ab0SAndrei Emeltchenko u32 control; 4580fb45de7dSAndrei Emeltchenko u16 tx_seq; 45810a708f8fSGustavo F. Padovan int len; 45820a708f8fSGustavo F. Padovan 4583baa7e1faSGustavo F. Padovan chan = l2cap_get_chan_by_scid(conn, cid); 458448454079SGustavo F. Padovan if (!chan) { 45850a708f8fSGustavo F. Padovan BT_DBG("unknown cid 0x%4.4x", cid); 45866be36555SAndrei Emeltchenko /* Drop packet and return */ 45873379013bSDan Carpenter kfree_skb(skb); 45886be36555SAndrei Emeltchenko return 0; 45890a708f8fSGustavo F. Padovan } 45900a708f8fSGustavo F. Padovan 45916be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 45920a708f8fSGustavo F. Padovan 459349208c9cSGustavo F. Padovan BT_DBG("chan %p, len %d", chan, skb->len); 45940a708f8fSGustavo F. Padovan 459589bc500eSGustavo F. Padovan if (chan->state != BT_CONNECTED) 45960a708f8fSGustavo F. Padovan goto drop; 45970a708f8fSGustavo F. Padovan 45980c1bc5c6SGustavo F. Padovan switch (chan->mode) { 45990a708f8fSGustavo F. Padovan case L2CAP_MODE_BASIC: 46000a708f8fSGustavo F. Padovan /* If socket recv buffers overflows we drop data here 46010a708f8fSGustavo F. Padovan * which is *bad* because L2CAP has to be reliable. 46020a708f8fSGustavo F. Padovan * But we don't have any other choice. L2CAP doesn't 46030a708f8fSGustavo F. Padovan * provide flow control mechanism. */ 46040a708f8fSGustavo F. Padovan 46050c1bc5c6SGustavo F. Padovan if (chan->imtu < skb->len) 46060a708f8fSGustavo F. Padovan goto drop; 46070a708f8fSGustavo F. Padovan 460823070494SGustavo F. Padovan if (!chan->ops->recv(chan->data, skb)) 46090a708f8fSGustavo F. Padovan goto done; 46100a708f8fSGustavo F. Padovan break; 46110a708f8fSGustavo F. Padovan 46120a708f8fSGustavo F. Padovan case L2CAP_MODE_ERTM: 46135ef8cb9eSAndrei Emeltchenko l2cap_ertm_data_rcv(chan, skb); 46140a708f8fSGustavo F. Padovan 46150a708f8fSGustavo F. Padovan goto done; 46160a708f8fSGustavo F. Padovan 46170a708f8fSGustavo F. Padovan case L2CAP_MODE_STREAMING: 461888843ab0SAndrei Emeltchenko control = __get_control(chan, skb->data); 461988843ab0SAndrei Emeltchenko skb_pull(skb, __ctrl_size(chan)); 46200a708f8fSGustavo F. Padovan len = skb->len; 46210a708f8fSGustavo F. Padovan 462247d1ec61SGustavo F. Padovan if (l2cap_check_fcs(chan, skb)) 46230a708f8fSGustavo F. Padovan goto drop; 46240a708f8fSGustavo F. Padovan 46257e0ef6eeSAndrei Emeltchenko if (__is_sar_start(chan, control)) 462603a51213SAndrei Emeltchenko len -= L2CAP_SDULEN_SIZE; 46270a708f8fSGustavo F. Padovan 462847d1ec61SGustavo F. Padovan if (chan->fcs == L2CAP_FCS_CRC16) 462903a51213SAndrei Emeltchenko len -= L2CAP_FCS_SIZE; 46300a708f8fSGustavo F. Padovan 4631793c2f1cSAndrei Emeltchenko if (len > chan->mps || len < 0 || __is_sframe(chan, control)) 46320a708f8fSGustavo F. Padovan goto drop; 46330a708f8fSGustavo F. Padovan 4634fb45de7dSAndrei Emeltchenko tx_seq = __get_txseq(chan, control); 46350a708f8fSGustavo F. Padovan 463684084a31SMat Martineau if (chan->expected_tx_seq != tx_seq) { 463784084a31SMat Martineau /* Frame(s) missing - must discard partial SDU */ 463884084a31SMat Martineau kfree_skb(chan->sdu); 463984084a31SMat Martineau chan->sdu = NULL; 464084084a31SMat Martineau chan->sdu_last_frag = NULL; 464184084a31SMat Martineau chan->sdu_len = 0; 464284084a31SMat Martineau 464384084a31SMat Martineau /* TODO: Notify userland of missing data */ 464484084a31SMat Martineau } 464584084a31SMat Martineau 4646836be934SAndrei Emeltchenko chan->expected_tx_seq = __next_seq(chan, tx_seq); 46470a708f8fSGustavo F. Padovan 464884084a31SMat Martineau if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE) 464984084a31SMat Martineau l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); 46500a708f8fSGustavo F. Padovan 46510a708f8fSGustavo F. Padovan goto done; 46520a708f8fSGustavo F. Padovan 46530a708f8fSGustavo F. Padovan default: 46540c1bc5c6SGustavo F. Padovan BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode); 46550a708f8fSGustavo F. Padovan break; 46560a708f8fSGustavo F. Padovan } 46570a708f8fSGustavo F. Padovan 46580a708f8fSGustavo F. Padovan drop: 46590a708f8fSGustavo F. Padovan kfree_skb(skb); 46600a708f8fSGustavo F. Padovan 46610a708f8fSGustavo F. Padovan done: 46626be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 46630a708f8fSGustavo F. Padovan 46640a708f8fSGustavo F. Padovan return 0; 46650a708f8fSGustavo F. Padovan } 46660a708f8fSGustavo F. Padovan 46670a708f8fSGustavo F. Padovan static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) 46680a708f8fSGustavo F. Padovan { 466923691d75SGustavo F. Padovan struct l2cap_chan *chan; 46700a708f8fSGustavo F. Padovan 4671c2287681SIdo Yariv chan = l2cap_global_chan_by_psm(0, psm, conn->src, conn->dst); 467223691d75SGustavo F. Padovan if (!chan) 46730a708f8fSGustavo F. Padovan goto drop; 46740a708f8fSGustavo F. Padovan 46755b4cedaaSAndrei Emeltchenko BT_DBG("chan %p, len %d", chan, skb->len); 46760a708f8fSGustavo F. Padovan 467789bc500eSGustavo F. Padovan if (chan->state != BT_BOUND && chan->state != BT_CONNECTED) 46780a708f8fSGustavo F. Padovan goto drop; 46790a708f8fSGustavo F. Padovan 4680e13e21dcSVinicius Costa Gomes if (chan->imtu < skb->len) 46810a708f8fSGustavo F. Padovan goto drop; 46820a708f8fSGustavo F. Padovan 468323070494SGustavo F. Padovan if (!chan->ops->recv(chan->data, skb)) 46845b4cedaaSAndrei Emeltchenko return 0; 46850a708f8fSGustavo F. Padovan 46860a708f8fSGustavo F. Padovan drop: 46870a708f8fSGustavo F. Padovan kfree_skb(skb); 46880a708f8fSGustavo F. Padovan 46890a708f8fSGustavo F. Padovan return 0; 46900a708f8fSGustavo F. Padovan } 46910a708f8fSGustavo F. Padovan 4692d9b88702SAndrei Emeltchenko static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid, 4693d9b88702SAndrei Emeltchenko struct sk_buff *skb) 46949f69bda6SGustavo F. Padovan { 469523691d75SGustavo F. Padovan struct l2cap_chan *chan; 46969f69bda6SGustavo F. Padovan 4697c2287681SIdo Yariv chan = l2cap_global_chan_by_scid(0, cid, conn->src, conn->dst); 469823691d75SGustavo F. Padovan if (!chan) 46999f69bda6SGustavo F. Padovan goto drop; 47009f69bda6SGustavo F. Padovan 47015b4cedaaSAndrei Emeltchenko BT_DBG("chan %p, len %d", chan, skb->len); 47029f69bda6SGustavo F. Padovan 470389bc500eSGustavo F. Padovan if (chan->state != BT_BOUND && chan->state != BT_CONNECTED) 47049f69bda6SGustavo F. Padovan goto drop; 47059f69bda6SGustavo F. Padovan 4706e13e21dcSVinicius Costa Gomes if (chan->imtu < skb->len) 47079f69bda6SGustavo F. Padovan goto drop; 47089f69bda6SGustavo F. Padovan 470923070494SGustavo F. Padovan if (!chan->ops->recv(chan->data, skb)) 47105b4cedaaSAndrei Emeltchenko return 0; 47119f69bda6SGustavo F. Padovan 47129f69bda6SGustavo F. Padovan drop: 47139f69bda6SGustavo F. Padovan kfree_skb(skb); 47149f69bda6SGustavo F. Padovan 47159f69bda6SGustavo F. Padovan return 0; 47169f69bda6SGustavo F. Padovan } 47179f69bda6SGustavo F. Padovan 47180a708f8fSGustavo F. Padovan static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) 47190a708f8fSGustavo F. Padovan { 47200a708f8fSGustavo F. Padovan struct l2cap_hdr *lh = (void *) skb->data; 47210a708f8fSGustavo F. Padovan u16 cid, len; 47220a708f8fSGustavo F. Padovan __le16 psm; 47230a708f8fSGustavo F. Padovan 47240a708f8fSGustavo F. Padovan skb_pull(skb, L2CAP_HDR_SIZE); 47250a708f8fSGustavo F. Padovan cid = __le16_to_cpu(lh->cid); 47260a708f8fSGustavo F. Padovan len = __le16_to_cpu(lh->len); 47270a708f8fSGustavo F. Padovan 47280a708f8fSGustavo F. Padovan if (len != skb->len) { 47290a708f8fSGustavo F. Padovan kfree_skb(skb); 47300a708f8fSGustavo F. Padovan return; 47310a708f8fSGustavo F. Padovan } 47320a708f8fSGustavo F. Padovan 47330a708f8fSGustavo F. Padovan BT_DBG("len %d, cid 0x%4.4x", len, cid); 47340a708f8fSGustavo F. Padovan 47350a708f8fSGustavo F. Padovan switch (cid) { 47363300d9a9SClaudio Takahasi case L2CAP_CID_LE_SIGNALING: 47370a708f8fSGustavo F. Padovan case L2CAP_CID_SIGNALING: 47380a708f8fSGustavo F. Padovan l2cap_sig_channel(conn, skb); 47390a708f8fSGustavo F. Padovan break; 47400a708f8fSGustavo F. Padovan 47410a708f8fSGustavo F. Padovan case L2CAP_CID_CONN_LESS: 4742097db76cSAndrei Emeltchenko psm = get_unaligned((__le16 *) skb->data); 47430a708f8fSGustavo F. Padovan skb_pull(skb, 2); 47440a708f8fSGustavo F. Padovan l2cap_conless_channel(conn, psm, skb); 47450a708f8fSGustavo F. Padovan break; 47460a708f8fSGustavo F. Padovan 47479f69bda6SGustavo F. Padovan case L2CAP_CID_LE_DATA: 47489f69bda6SGustavo F. Padovan l2cap_att_channel(conn, cid, skb); 47499f69bda6SGustavo F. Padovan break; 47509f69bda6SGustavo F. Padovan 4751b501d6a1SAnderson Briglia case L2CAP_CID_SMP: 4752b501d6a1SAnderson Briglia if (smp_sig_channel(conn, skb)) 4753b501d6a1SAnderson Briglia l2cap_conn_del(conn->hcon, EACCES); 4754b501d6a1SAnderson Briglia break; 4755b501d6a1SAnderson Briglia 47560a708f8fSGustavo F. Padovan default: 47570a708f8fSGustavo F. Padovan l2cap_data_channel(conn, cid, skb); 47580a708f8fSGustavo F. Padovan break; 47590a708f8fSGustavo F. Padovan } 47600a708f8fSGustavo F. Padovan } 47610a708f8fSGustavo F. Padovan 47620a708f8fSGustavo F. Padovan /* ---- L2CAP interface with lower layer (HCI) ---- */ 47630a708f8fSGustavo F. Padovan 4764686ebf28SUlisses Furquim int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) 47650a708f8fSGustavo F. Padovan { 47660a708f8fSGustavo F. Padovan int exact = 0, lm1 = 0, lm2 = 0; 476723691d75SGustavo F. Padovan struct l2cap_chan *c; 47680a708f8fSGustavo F. Padovan 47690a708f8fSGustavo F. Padovan BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); 47700a708f8fSGustavo F. Padovan 47710a708f8fSGustavo F. Padovan /* Find listening sockets and check their link_mode */ 477223691d75SGustavo F. Padovan read_lock(&chan_list_lock); 477323691d75SGustavo F. Padovan list_for_each_entry(c, &chan_list, global_l) { 477423691d75SGustavo F. Padovan struct sock *sk = c->sk; 47754343478fSGustavo F. Padovan 477689bc500eSGustavo F. Padovan if (c->state != BT_LISTEN) 47770a708f8fSGustavo F. Padovan continue; 47780a708f8fSGustavo F. Padovan 47790a708f8fSGustavo F. Padovan if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { 47800a708f8fSGustavo F. Padovan lm1 |= HCI_LM_ACCEPT; 478143bd0f32SAndrei Emeltchenko if (test_bit(FLAG_ROLE_SWITCH, &c->flags)) 47820a708f8fSGustavo F. Padovan lm1 |= HCI_LM_MASTER; 47830a708f8fSGustavo F. Padovan exact++; 47840a708f8fSGustavo F. Padovan } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { 47850a708f8fSGustavo F. Padovan lm2 |= HCI_LM_ACCEPT; 478643bd0f32SAndrei Emeltchenko if (test_bit(FLAG_ROLE_SWITCH, &c->flags)) 47870a708f8fSGustavo F. Padovan lm2 |= HCI_LM_MASTER; 47880a708f8fSGustavo F. Padovan } 47890a708f8fSGustavo F. Padovan } 479023691d75SGustavo F. Padovan read_unlock(&chan_list_lock); 47910a708f8fSGustavo F. Padovan 47920a708f8fSGustavo F. Padovan return exact ? lm1 : lm2; 47930a708f8fSGustavo F. Padovan } 47940a708f8fSGustavo F. Padovan 4795686ebf28SUlisses Furquim int l2cap_connect_cfm(struct hci_conn *hcon, u8 status) 47960a708f8fSGustavo F. Padovan { 47970a708f8fSGustavo F. Padovan struct l2cap_conn *conn; 47980a708f8fSGustavo F. Padovan 47990a708f8fSGustavo F. Padovan BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); 48000a708f8fSGustavo F. Padovan 48010a708f8fSGustavo F. Padovan if (!status) { 48020a708f8fSGustavo F. Padovan conn = l2cap_conn_add(hcon, status); 48030a708f8fSGustavo F. Padovan if (conn) 48040a708f8fSGustavo F. Padovan l2cap_conn_ready(conn); 48050a708f8fSGustavo F. Padovan } else 4806e175072fSJoe Perches l2cap_conn_del(hcon, bt_to_errno(status)); 48070a708f8fSGustavo F. Padovan 48080a708f8fSGustavo F. Padovan return 0; 48090a708f8fSGustavo F. Padovan } 48100a708f8fSGustavo F. Padovan 4811686ebf28SUlisses Furquim int l2cap_disconn_ind(struct hci_conn *hcon) 48120a708f8fSGustavo F. Padovan { 48130a708f8fSGustavo F. Padovan struct l2cap_conn *conn = hcon->l2cap_data; 48140a708f8fSGustavo F. Padovan 48150a708f8fSGustavo F. Padovan BT_DBG("hcon %p", hcon); 48160a708f8fSGustavo F. Padovan 4817686ebf28SUlisses Furquim if (!conn) 48189f5a0d7bSAndrei Emeltchenko return HCI_ERROR_REMOTE_USER_TERM; 48190a708f8fSGustavo F. Padovan return conn->disc_reason; 48200a708f8fSGustavo F. Padovan } 48210a708f8fSGustavo F. Padovan 4822686ebf28SUlisses Furquim int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) 48230a708f8fSGustavo F. Padovan { 48240a708f8fSGustavo F. Padovan BT_DBG("hcon %p reason %d", hcon, reason); 48250a708f8fSGustavo F. Padovan 4826e175072fSJoe Perches l2cap_conn_del(hcon, bt_to_errno(reason)); 48270a708f8fSGustavo F. Padovan return 0; 48280a708f8fSGustavo F. Padovan } 48290a708f8fSGustavo F. Padovan 48304343478fSGustavo F. Padovan static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) 48310a708f8fSGustavo F. Padovan { 4832715ec005SGustavo F. Padovan if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) 48330a708f8fSGustavo F. Padovan return; 48340a708f8fSGustavo F. Padovan 48350a708f8fSGustavo F. Padovan if (encrypt == 0x00) { 48364343478fSGustavo F. Padovan if (chan->sec_level == BT_SECURITY_MEDIUM) { 4837ba13ccd9SMarcel Holtmann __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); 48384343478fSGustavo F. Padovan } else if (chan->sec_level == BT_SECURITY_HIGH) 48390f852724SGustavo F. Padovan l2cap_chan_close(chan, ECONNREFUSED); 48400a708f8fSGustavo F. Padovan } else { 48414343478fSGustavo F. Padovan if (chan->sec_level == BT_SECURITY_MEDIUM) 4842c9b66675SGustavo F. Padovan __clear_chan_timer(chan); 48430a708f8fSGustavo F. Padovan } 48440a708f8fSGustavo F. Padovan } 48450a708f8fSGustavo F. Padovan 4846686ebf28SUlisses Furquim int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) 48470a708f8fSGustavo F. Padovan { 48480a708f8fSGustavo F. Padovan struct l2cap_conn *conn = hcon->l2cap_data; 484948454079SGustavo F. Padovan struct l2cap_chan *chan; 48500a708f8fSGustavo F. Padovan 48510a708f8fSGustavo F. Padovan if (!conn) 48520a708f8fSGustavo F. Padovan return 0; 48530a708f8fSGustavo F. Padovan 48540a708f8fSGustavo F. Padovan BT_DBG("conn %p", conn); 48550a708f8fSGustavo F. Padovan 4856160dc6acSVinicius Costa Gomes if (hcon->type == LE_LINK) { 485735d4adccSHemant Gupta if (!status && encrypt) 4858160dc6acSVinicius Costa Gomes smp_distribute_keys(conn, 0); 485917cd3f37SUlisses Furquim cancel_delayed_work(&conn->security_timer); 4860160dc6acSVinicius Costa Gomes } 4861160dc6acSVinicius Costa Gomes 48623df91ea2SAndrei Emeltchenko mutex_lock(&conn->chan_lock); 48630a708f8fSGustavo F. Padovan 48643df91ea2SAndrei Emeltchenko list_for_each_entry(chan, &conn->chan_l, list) { 48656be36555SAndrei Emeltchenko l2cap_chan_lock(chan); 48660a708f8fSGustavo F. Padovan 4867f1cb9af5SVinicius Costa Gomes BT_DBG("chan->scid %d", chan->scid); 4868f1cb9af5SVinicius Costa Gomes 4869f1cb9af5SVinicius Costa Gomes if (chan->scid == L2CAP_CID_LE_DATA) { 4870f1cb9af5SVinicius Costa Gomes if (!status && encrypt) { 4871f1cb9af5SVinicius Costa Gomes chan->sec_level = hcon->sec_level; 4872cf4cd009SAndrei Emeltchenko l2cap_chan_ready(chan); 4873f1cb9af5SVinicius Costa Gomes } 4874f1cb9af5SVinicius Costa Gomes 48756be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 4876f1cb9af5SVinicius Costa Gomes continue; 4877f1cb9af5SVinicius Costa Gomes } 4878f1cb9af5SVinicius Costa Gomes 4879c1360a1cSGustavo F. Padovan if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) { 48806be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 48810a708f8fSGustavo F. Padovan continue; 48820a708f8fSGustavo F. Padovan } 48830a708f8fSGustavo F. Padovan 488489bc500eSGustavo F. Padovan if (!status && (chan->state == BT_CONNECTED || 488589bc500eSGustavo F. Padovan chan->state == BT_CONFIG)) { 48864343478fSGustavo F. Padovan l2cap_check_encryption(chan, encrypt); 48876be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 48880a708f8fSGustavo F. Padovan continue; 48890a708f8fSGustavo F. Padovan } 48900a708f8fSGustavo F. Padovan 489189bc500eSGustavo F. Padovan if (chan->state == BT_CONNECT) { 48920a708f8fSGustavo F. Padovan if (!status) { 48939b27f350SAndrei Emeltchenko l2cap_send_conn_req(chan); 48940a708f8fSGustavo F. Padovan } else { 4895ba13ccd9SMarcel Holtmann __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); 48960a708f8fSGustavo F. Padovan } 489789bc500eSGustavo F. Padovan } else if (chan->state == BT_CONNECT2) { 48986be36555SAndrei Emeltchenko struct sock *sk = chan->sk; 48990a708f8fSGustavo F. Padovan struct l2cap_conn_rsp rsp; 4900df3c3931SJohan Hedberg __u16 res, stat; 49010a708f8fSGustavo F. Padovan 49026be36555SAndrei Emeltchenko lock_sock(sk); 49036be36555SAndrei Emeltchenko 49040a708f8fSGustavo F. Padovan if (!status) { 4905df3c3931SJohan Hedberg if (bt_sk(sk)->defer_setup) { 4906df3c3931SJohan Hedberg struct sock *parent = bt_sk(sk)->parent; 4907df3c3931SJohan Hedberg res = L2CAP_CR_PEND; 4908df3c3931SJohan Hedberg stat = L2CAP_CS_AUTHOR_PEND; 490905e9a2f6SIlia Kolomisnky if (parent) 4910df3c3931SJohan Hedberg parent->sk_data_ready(parent, 0); 4911df3c3931SJohan Hedberg } else { 49120e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_CONFIG); 4913df3c3931SJohan Hedberg res = L2CAP_CR_SUCCESS; 4914df3c3931SJohan Hedberg stat = L2CAP_CS_NO_INFO; 4915df3c3931SJohan Hedberg } 49160a708f8fSGustavo F. Padovan } else { 49170e587be7SAndrei Emeltchenko __l2cap_state_change(chan, BT_DISCONN); 4918ba13ccd9SMarcel Holtmann __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); 4919df3c3931SJohan Hedberg res = L2CAP_CR_SEC_BLOCK; 4920df3c3931SJohan Hedberg stat = L2CAP_CS_NO_INFO; 49210a708f8fSGustavo F. Padovan } 49220a708f8fSGustavo F. Padovan 49236be36555SAndrei Emeltchenko release_sock(sk); 49246be36555SAndrei Emeltchenko 4925fe4128e0SGustavo F. Padovan rsp.scid = cpu_to_le16(chan->dcid); 4926fe4128e0SGustavo F. Padovan rsp.dcid = cpu_to_le16(chan->scid); 4927df3c3931SJohan Hedberg rsp.result = cpu_to_le16(res); 4928df3c3931SJohan Hedberg rsp.status = cpu_to_le16(stat); 4929fc7f8a7eSGustavo F. Padovan l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, 4930fc7f8a7eSGustavo F. Padovan sizeof(rsp), &rsp); 49310a708f8fSGustavo F. Padovan } 49320a708f8fSGustavo F. Padovan 49336be36555SAndrei Emeltchenko l2cap_chan_unlock(chan); 49340a708f8fSGustavo F. Padovan } 49350a708f8fSGustavo F. Padovan 49363df91ea2SAndrei Emeltchenko mutex_unlock(&conn->chan_lock); 49370a708f8fSGustavo F. Padovan 49380a708f8fSGustavo F. Padovan return 0; 49390a708f8fSGustavo F. Padovan } 49400a708f8fSGustavo F. Padovan 4941686ebf28SUlisses Furquim int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) 49420a708f8fSGustavo F. Padovan { 49430a708f8fSGustavo F. Padovan struct l2cap_conn *conn = hcon->l2cap_data; 49440a708f8fSGustavo F. Padovan 49450a708f8fSGustavo F. Padovan if (!conn) 49460a708f8fSGustavo F. Padovan conn = l2cap_conn_add(hcon, 0); 49470a708f8fSGustavo F. Padovan 49480a708f8fSGustavo F. Padovan if (!conn) 49490a708f8fSGustavo F. Padovan goto drop; 49500a708f8fSGustavo F. Padovan 49510a708f8fSGustavo F. Padovan BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags); 49520a708f8fSGustavo F. Padovan 49530a708f8fSGustavo F. Padovan if (!(flags & ACL_CONT)) { 49540a708f8fSGustavo F. Padovan struct l2cap_hdr *hdr; 495548454079SGustavo F. Padovan struct l2cap_chan *chan; 49560a708f8fSGustavo F. Padovan u16 cid; 49570a708f8fSGustavo F. Padovan int len; 49580a708f8fSGustavo F. Padovan 49590a708f8fSGustavo F. Padovan if (conn->rx_len) { 49600a708f8fSGustavo F. Padovan BT_ERR("Unexpected start frame (len %d)", skb->len); 49610a708f8fSGustavo F. Padovan kfree_skb(conn->rx_skb); 49620a708f8fSGustavo F. Padovan conn->rx_skb = NULL; 49630a708f8fSGustavo F. Padovan conn->rx_len = 0; 49640a708f8fSGustavo F. Padovan l2cap_conn_unreliable(conn, ECOMM); 49650a708f8fSGustavo F. Padovan } 49660a708f8fSGustavo F. Padovan 49670a708f8fSGustavo F. Padovan /* Start fragment always begin with Basic L2CAP header */ 49680a708f8fSGustavo F. Padovan if (skb->len < L2CAP_HDR_SIZE) { 49690a708f8fSGustavo F. Padovan BT_ERR("Frame is too short (len %d)", skb->len); 49700a708f8fSGustavo F. Padovan l2cap_conn_unreliable(conn, ECOMM); 49710a708f8fSGustavo F. Padovan goto drop; 49720a708f8fSGustavo F. Padovan } 49730a708f8fSGustavo F. Padovan 49740a708f8fSGustavo F. Padovan hdr = (struct l2cap_hdr *) skb->data; 49750a708f8fSGustavo F. Padovan len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE; 49760a708f8fSGustavo F. Padovan cid = __le16_to_cpu(hdr->cid); 49770a708f8fSGustavo F. Padovan 49780a708f8fSGustavo F. Padovan if (len == skb->len) { 49790a708f8fSGustavo F. Padovan /* Complete frame received */ 49800a708f8fSGustavo F. Padovan l2cap_recv_frame(conn, skb); 49810a708f8fSGustavo F. Padovan return 0; 49820a708f8fSGustavo F. Padovan } 49830a708f8fSGustavo F. Padovan 49840a708f8fSGustavo F. Padovan BT_DBG("Start: total len %d, frag len %d", len, skb->len); 49850a708f8fSGustavo F. Padovan 49860a708f8fSGustavo F. Padovan if (skb->len > len) { 49870a708f8fSGustavo F. Padovan BT_ERR("Frame is too long (len %d, expected len %d)", 49880a708f8fSGustavo F. Padovan skb->len, len); 49890a708f8fSGustavo F. Padovan l2cap_conn_unreliable(conn, ECOMM); 49900a708f8fSGustavo F. Padovan goto drop; 49910a708f8fSGustavo F. Padovan } 49920a708f8fSGustavo F. Padovan 4993baa7e1faSGustavo F. Padovan chan = l2cap_get_chan_by_scid(conn, cid); 49940a708f8fSGustavo F. Padovan 499548454079SGustavo F. Padovan if (chan && chan->sk) { 499648454079SGustavo F. Padovan struct sock *sk = chan->sk; 49973df91ea2SAndrei Emeltchenko lock_sock(sk); 499848454079SGustavo F. Padovan 49990c1bc5c6SGustavo F. Padovan if (chan->imtu < len - L2CAP_HDR_SIZE) { 500048454079SGustavo F. Padovan BT_ERR("Frame exceeding recv MTU (len %d, " 500148454079SGustavo F. Padovan "MTU %d)", len, 50020c1bc5c6SGustavo F. Padovan chan->imtu); 5003aa2ac881SGustavo F. Padovan release_sock(sk); 50040a708f8fSGustavo F. Padovan l2cap_conn_unreliable(conn, ECOMM); 50050a708f8fSGustavo F. Padovan goto drop; 50060a708f8fSGustavo F. Padovan } 5007aa2ac881SGustavo F. Padovan release_sock(sk); 500848454079SGustavo F. Padovan } 50090a708f8fSGustavo F. Padovan 50100a708f8fSGustavo F. Padovan /* Allocate skb for the complete frame (with header) */ 50110a708f8fSGustavo F. Padovan conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); 50120a708f8fSGustavo F. Padovan if (!conn->rx_skb) 50130a708f8fSGustavo F. Padovan goto drop; 50140a708f8fSGustavo F. Padovan 50150a708f8fSGustavo F. Padovan skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), 50160a708f8fSGustavo F. Padovan skb->len); 50170a708f8fSGustavo F. Padovan conn->rx_len = len - skb->len; 50180a708f8fSGustavo F. Padovan } else { 50190a708f8fSGustavo F. Padovan BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len); 50200a708f8fSGustavo F. Padovan 50210a708f8fSGustavo F. Padovan if (!conn->rx_len) { 50220a708f8fSGustavo F. Padovan BT_ERR("Unexpected continuation frame (len %d)", skb->len); 50230a708f8fSGustavo F. Padovan l2cap_conn_unreliable(conn, ECOMM); 50240a708f8fSGustavo F. Padovan goto drop; 50250a708f8fSGustavo F. Padovan } 50260a708f8fSGustavo F. Padovan 50270a708f8fSGustavo F. Padovan if (skb->len > conn->rx_len) { 50280a708f8fSGustavo F. Padovan BT_ERR("Fragment is too long (len %d, expected %d)", 50290a708f8fSGustavo F. Padovan skb->len, conn->rx_len); 50300a708f8fSGustavo F. Padovan kfree_skb(conn->rx_skb); 50310a708f8fSGustavo F. Padovan conn->rx_skb = NULL; 50320a708f8fSGustavo F. Padovan conn->rx_len = 0; 50330a708f8fSGustavo F. Padovan l2cap_conn_unreliable(conn, ECOMM); 50340a708f8fSGustavo F. Padovan goto drop; 50350a708f8fSGustavo F. Padovan } 50360a708f8fSGustavo F. Padovan 50370a708f8fSGustavo F. Padovan skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len), 50380a708f8fSGustavo F. Padovan skb->len); 50390a708f8fSGustavo F. Padovan conn->rx_len -= skb->len; 50400a708f8fSGustavo F. Padovan 50410a708f8fSGustavo F. Padovan if (!conn->rx_len) { 50420a708f8fSGustavo F. Padovan /* Complete frame received */ 50430a708f8fSGustavo F. Padovan l2cap_recv_frame(conn, conn->rx_skb); 50440a708f8fSGustavo F. Padovan conn->rx_skb = NULL; 50450a708f8fSGustavo F. Padovan } 50460a708f8fSGustavo F. Padovan } 50470a708f8fSGustavo F. Padovan 50480a708f8fSGustavo F. Padovan drop: 50490a708f8fSGustavo F. Padovan kfree_skb(skb); 50500a708f8fSGustavo F. Padovan return 0; 50510a708f8fSGustavo F. Padovan } 50520a708f8fSGustavo F. Padovan 50530a708f8fSGustavo F. Padovan static int l2cap_debugfs_show(struct seq_file *f, void *p) 50540a708f8fSGustavo F. Padovan { 505523691d75SGustavo F. Padovan struct l2cap_chan *c; 50560a708f8fSGustavo F. Padovan 5057333055f2SGustavo F. Padovan read_lock(&chan_list_lock); 50580a708f8fSGustavo F. Padovan 505923691d75SGustavo F. Padovan list_for_each_entry(c, &chan_list, global_l) { 506023691d75SGustavo F. Padovan struct sock *sk = c->sk; 50610a708f8fSGustavo F. Padovan 5062903d343eSGustavo F. Padovan seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", 50630a708f8fSGustavo F. Padovan batostr(&bt_sk(sk)->src), 50640a708f8fSGustavo F. Padovan batostr(&bt_sk(sk)->dst), 506589bc500eSGustavo F. Padovan c->state, __le16_to_cpu(c->psm), 506623691d75SGustavo F. Padovan c->scid, c->dcid, c->imtu, c->omtu, 506723691d75SGustavo F. Padovan c->sec_level, c->mode); 50680a708f8fSGustavo F. Padovan } 50690a708f8fSGustavo F. Padovan 5070333055f2SGustavo F. Padovan read_unlock(&chan_list_lock); 50710a708f8fSGustavo F. Padovan 50720a708f8fSGustavo F. Padovan return 0; 50730a708f8fSGustavo F. Padovan } 50740a708f8fSGustavo F. Padovan 50750a708f8fSGustavo F. Padovan static int l2cap_debugfs_open(struct inode *inode, struct file *file) 50760a708f8fSGustavo F. Padovan { 50770a708f8fSGustavo F. Padovan return single_open(file, l2cap_debugfs_show, inode->i_private); 50780a708f8fSGustavo F. Padovan } 50790a708f8fSGustavo F. Padovan 50800a708f8fSGustavo F. Padovan static const struct file_operations l2cap_debugfs_fops = { 50810a708f8fSGustavo F. Padovan .open = l2cap_debugfs_open, 50820a708f8fSGustavo F. Padovan .read = seq_read, 50830a708f8fSGustavo F. Padovan .llseek = seq_lseek, 50840a708f8fSGustavo F. Padovan .release = single_release, 50850a708f8fSGustavo F. Padovan }; 50860a708f8fSGustavo F. Padovan 50870a708f8fSGustavo F. Padovan static struct dentry *l2cap_debugfs; 50880a708f8fSGustavo F. Padovan 508964274518SGustavo F. Padovan int __init l2cap_init(void) 50900a708f8fSGustavo F. Padovan { 50910a708f8fSGustavo F. Padovan int err; 50920a708f8fSGustavo F. Padovan 5093bb58f747SGustavo F. Padovan err = l2cap_init_sockets(); 50940a708f8fSGustavo F. Padovan if (err < 0) 50950a708f8fSGustavo F. Padovan return err; 50960a708f8fSGustavo F. Padovan 50970a708f8fSGustavo F. Padovan if (bt_debugfs) { 50980a708f8fSGustavo F. Padovan l2cap_debugfs = debugfs_create_file("l2cap", 0444, 50990a708f8fSGustavo F. Padovan bt_debugfs, NULL, &l2cap_debugfs_fops); 51000a708f8fSGustavo F. Padovan if (!l2cap_debugfs) 51010a708f8fSGustavo F. Padovan BT_ERR("Failed to create L2CAP debug file"); 51020a708f8fSGustavo F. Padovan } 51030a708f8fSGustavo F. Padovan 51040a708f8fSGustavo F. Padovan return 0; 51050a708f8fSGustavo F. Padovan } 51060a708f8fSGustavo F. Padovan 510764274518SGustavo F. Padovan void l2cap_exit(void) 51080a708f8fSGustavo F. Padovan { 51090a708f8fSGustavo F. Padovan debugfs_remove(l2cap_debugfs); 5110bb58f747SGustavo F. Padovan l2cap_cleanup_sockets(); 51110a708f8fSGustavo F. Padovan } 51120a708f8fSGustavo F. Padovan 51130a708f8fSGustavo F. Padovan module_param(disable_ertm, bool, 0644); 51140a708f8fSGustavo F. Padovan MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode"); 5115