blob: cb68b27edc9b30f8e14e8893348f25bf130318eb [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
7 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation;
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090017 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090022 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 SOFTWARE IS DISCLAIMED.
25*/
26
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020027/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30
31#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/sched.h>
36#include <linux/slab.h>
37#include <linux/poll.h>
38#include <linux/fcntl.h>
39#include <linux/init.h>
40#include <linux/interrupt.h>
41#include <linux/socket.h>
42#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080044#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010045#include <linux/debugfs.h>
46#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030047#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030048#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/sock.h>
50
51#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/unaligned.h>
53
54#include <net/bluetooth/bluetooth.h>
55#include <net/bluetooth/hci_core.h>
56#include <net/bluetooth/l2cap.h>
57
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020058int disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020059
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070060static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Marcel Holtmanne1027a72009-02-09 09:18:02 +010061static u8 l2cap_fixed_chan[8] = { 0x02, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Gustavo F. Padovan1890d362010-05-01 16:15:44 -030063static struct workqueue_struct *_busy_wq;
64
Johannes Bergb5ad8b72011-06-01 08:54:45 +020065static LIST_HEAD(chan_list);
66static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Gustavo F. Padovan1890d362010-05-01 16:15:44 -030068static void l2cap_busy_work(struct work_struct *work);
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
71 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030072static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
73 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030074static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030075static void l2cap_send_disconn_req(struct l2cap_conn *conn,
76 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030078static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
79
Marcel Holtmann01394182006-07-03 10:02:46 +020080/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030081
82static inline void chan_hold(struct l2cap_chan *c)
83{
84 atomic_inc(&c->refcnt);
85}
86
87static inline void chan_put(struct l2cap_chan *c)
88{
89 if (atomic_dec_and_test(&c->refcnt))
90 kfree(c);
91}
92
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030093static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020094{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030095 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030096
97 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030098 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030099 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200100 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300101 return NULL;
102
Marcel Holtmann01394182006-07-03 10:02:46 +0200103}
104
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300105static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200106{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300107 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300108
109 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300110 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300111 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200112 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300113 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200114}
115
116/* Find channel with given SCID.
117 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300118static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200119{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300120 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300121
122 read_lock(&conn->chan_lock);
123 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300124 if (c)
125 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300126 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300127 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200128}
129
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300130static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200131{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300132 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300133
134 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300135 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300136 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200137 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300138 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200139}
140
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300141static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200142{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300143 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300144
145 read_lock(&conn->chan_lock);
146 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300147 if (c)
148 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300149 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300150 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200151}
152
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300153static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300154{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300155 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300156
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300157 list_for_each_entry(c, &chan_list, global_l) {
158 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300159 goto found;
160 }
161
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300162 c = NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300163found:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300164 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300165}
166
167int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
168{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300169 int err;
170
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300171 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300172
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300173 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300174 err = -EADDRINUSE;
175 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300176 }
177
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300178 if (psm) {
179 chan->psm = psm;
180 chan->sport = psm;
181 err = 0;
182 } else {
183 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300184
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300185 err = -EINVAL;
186 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300187 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300188 chan->psm = cpu_to_le16(p);
189 chan->sport = cpu_to_le16(p);
190 err = 0;
191 break;
192 }
193 }
194
195done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300196 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300197 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300198}
199
200int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
201{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300202 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300203
204 chan->scid = scid;
205
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300206 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300207
208 return 0;
209}
210
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300211static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200212{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300213 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200214
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300215 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300216 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200217 return cid;
218 }
219
220 return 0;
221}
222
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300223static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300224{
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300225 BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
226
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300227 if (!mod_timer(timer, jiffies + timeout))
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300228 chan_hold(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300229}
230
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300231static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300232{
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300233 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300234
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300235 if (timer_pending(timer) && del_timer(timer))
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300236 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300237}
238
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300239static void l2cap_state_change(struct l2cap_chan *chan, int state)
240{
241 chan->state = state;
242 chan->ops->state_change(chan->data, state);
243}
244
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300245static void l2cap_chan_timeout(unsigned long arg)
246{
247 struct l2cap_chan *chan = (struct l2cap_chan *) arg;
248 struct sock *sk = chan->sk;
249 int reason;
250
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300251 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300252
253 bh_lock_sock(sk);
254
255 if (sock_owned_by_user(sk)) {
256 /* sk is owned by user. Try again later */
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300257 __set_chan_timer(chan, HZ / 5);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300258 bh_unlock_sock(sk);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300259 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300260 return;
261 }
262
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300263 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300264 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300265 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300266 chan->sec_level != BT_SECURITY_SDP)
267 reason = ECONNREFUSED;
268 else
269 reason = ETIMEDOUT;
270
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300271 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300272
273 bh_unlock_sock(sk);
274
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300275 chan->ops->close(chan->data);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300276 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300277}
278
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300279struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200280{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300281 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200282
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300283 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
284 if (!chan)
285 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200286
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300287 chan->sk = sk;
288
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300289 write_lock_bh(&chan_list_lock);
290 list_add(&chan->global_l, &chan_list);
291 write_unlock_bh(&chan_list_lock);
292
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300293 setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
294
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300295 chan->state = BT_OPEN;
296
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300297 atomic_set(&chan->refcnt, 1);
298
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300299 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200300}
301
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300302void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300303{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300304 write_lock_bh(&chan_list_lock);
305 list_del(&chan->global_l);
306 write_unlock_bh(&chan_list_lock);
307
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300308 chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300309}
310
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300311static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200312{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300313 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300314 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200315
Marcel Holtmann2950f212009-02-12 14:02:50 +0100316 conn->disc_reason = 0x13;
317
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300318 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200319
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300320 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300321 if (conn->hcon->type == LE_LINK) {
322 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300323 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300324 chan->scid = L2CAP_CID_LE_DATA;
325 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300326 } else {
327 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300328 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300329 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300330 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300331 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200332 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300333 chan->scid = L2CAP_CID_CONN_LESS;
334 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300335 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200336 } else {
337 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300338 chan->scid = L2CAP_CID_SIGNALING;
339 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300340 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200341 }
342
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300343 chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300344
345 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200346}
347
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900348/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200349 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300350static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200351{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300352 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300353 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200354 struct sock *parent = bt_sk(sk)->parent;
355
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300356 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200357
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300358 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200359
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900360 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300361 /* Delete from channel list */
362 write_lock_bh(&conn->chan_lock);
363 list_del(&chan->list);
364 write_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300365 chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300366
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300367 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200368 hci_conn_put(conn->hcon);
369 }
370
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300371 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200372 sock_set_flag(sk, SOCK_ZAPPED);
373
374 if (err)
375 sk->sk_err = err;
376
377 if (parent) {
378 bt_accept_unlink(sk);
379 parent->sk_data_ready(parent, 0);
380 } else
381 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300382
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300383 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE &&
384 chan->conf_state & L2CAP_CONF_INPUT_DONE))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300385 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300386
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300387 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300388
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300389 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300390 struct srej_list *l, *tmp;
391
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300392 __clear_retrans_timer(chan);
393 __clear_monitor_timer(chan);
394 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300395
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300396 skb_queue_purge(&chan->srej_q);
397 skb_queue_purge(&chan->busy_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300398
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300399 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300400 list_del(&l->list);
401 kfree(l);
402 }
403 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200404}
405
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300406static void l2cap_chan_cleanup_listen(struct sock *parent)
407{
408 struct sock *sk;
409
410 BT_DBG("parent %p", parent);
411
412 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300413 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300414 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300415 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300416 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300417 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300418 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300419 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300420 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300421}
422
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300423void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300424{
425 struct l2cap_conn *conn = chan->conn;
426 struct sock *sk = chan->sk;
427
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300428 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300429
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300430 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300431 case BT_LISTEN:
432 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300433
434 l2cap_state_change(chan, BT_CLOSED);
435 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300436 break;
437
438 case BT_CONNECTED:
439 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300440 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300441 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300442 __clear_chan_timer(chan);
443 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300444 l2cap_send_disconn_req(conn, chan, reason);
445 } else
446 l2cap_chan_del(chan, reason);
447 break;
448
449 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300450 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300451 conn->hcon->type == ACL_LINK) {
452 struct l2cap_conn_rsp rsp;
453 __u16 result;
454
455 if (bt_sk(sk)->defer_setup)
456 result = L2CAP_CR_SEC_BLOCK;
457 else
458 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300459 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300460
461 rsp.scid = cpu_to_le16(chan->dcid);
462 rsp.dcid = cpu_to_le16(chan->scid);
463 rsp.result = cpu_to_le16(result);
464 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
465 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
466 sizeof(rsp), &rsp);
467 }
468
469 l2cap_chan_del(chan, reason);
470 break;
471
472 case BT_CONNECT:
473 case BT_DISCONN:
474 l2cap_chan_del(chan, reason);
475 break;
476
477 default:
478 sock_set_flag(sk, SOCK_ZAPPED);
479 break;
480 }
481}
482
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300483static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530484{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300485 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300486 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530487 case BT_SECURITY_HIGH:
488 return HCI_AT_DEDICATED_BONDING_MITM;
489 case BT_SECURITY_MEDIUM:
490 return HCI_AT_DEDICATED_BONDING;
491 default:
492 return HCI_AT_NO_BONDING;
493 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300494 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300495 if (chan->sec_level == BT_SECURITY_LOW)
496 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530497
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300498 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530499 return HCI_AT_NO_BONDING_MITM;
500 else
501 return HCI_AT_NO_BONDING;
502 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300503 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530504 case BT_SECURITY_HIGH:
505 return HCI_AT_GENERAL_BONDING_MITM;
506 case BT_SECURITY_MEDIUM:
507 return HCI_AT_GENERAL_BONDING;
508 default:
509 return HCI_AT_NO_BONDING;
510 }
511 }
512}
513
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200514/* Service level security */
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300515static inline int l2cap_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200516{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300517 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100518 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200519
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300520 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100521
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300522 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200523}
524
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200525static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200526{
527 u8 id;
528
529 /* Get next available identificator.
530 * 1 - 128 are used by kernel.
531 * 129 - 199 are reserved.
532 * 200 - 254 are used by utilities like l2ping, etc.
533 */
534
535 spin_lock_bh(&conn->lock);
536
537 if (++conn->tx_ident > 128)
538 conn->tx_ident = 1;
539
540 id = conn->tx_ident;
541
542 spin_unlock_bh(&conn->lock);
543
544 return id;
545}
546
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300547static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200548{
549 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200550 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200551
552 BT_DBG("code 0x%2.2x", code);
553
554 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300555 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200556
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200557 if (lmp_no_flush_capable(conn->hcon->hdev))
558 flags = ACL_START_NO_FLUSH;
559 else
560 flags = ACL_START;
561
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700562 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
563
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200564 hci_send_acl(conn->hcon, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200565}
566
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300567static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300568{
569 struct sk_buff *skb;
570 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300571 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300572 int count, hlen = L2CAP_HDR_SIZE + 2;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200573 u8 flags;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300574
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300575 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300576 return;
577
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300578 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300579 hlen += 2;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300580
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300581 BT_DBG("chan %p, control 0x%2.2x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300582
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300583 count = min_t(unsigned int, conn->mtu, hlen);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300584 control |= L2CAP_CTRL_FRAME_TYPE;
585
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300586 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300587 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300588 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300589 }
590
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300591 if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300592 control |= L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300593 chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300594 }
595
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300596 skb = bt_skb_alloc(count, GFP_ATOMIC);
597 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300598 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300599
600 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300601 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300602 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300603 put_unaligned_le16(control, skb_put(skb, 2));
604
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300605 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300606 u16 fcs = crc16(0, (u8 *)lh, count - 2);
607 put_unaligned_le16(fcs, skb_put(skb, 2));
608 }
609
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200610 if (lmp_no_flush_capable(conn->hcon->hdev))
611 flags = ACL_START_NO_FLUSH;
612 else
613 flags = ACL_START;
614
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700615 bt_cb(skb)->force_active = chan->force_active;
616
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300617 hci_send_acl(chan->conn->hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300618}
619
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300620static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300621{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300622 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300623 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300624 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300625 } else
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300626 control |= L2CAP_SUPER_RCV_READY;
627
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -0300628 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300629
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300630 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300631}
632
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300633static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300634{
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300635 return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300636}
637
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300638static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200639{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300640 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200641
642 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100643 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
644 return;
645
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300646 if (l2cap_check_security(chan) &&
647 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200648 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300649 req.scid = cpu_to_le16(chan->scid);
650 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200651
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300652 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300653 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200654
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300655 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
656 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200657 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200658 } else {
659 struct l2cap_info_req req;
660 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
661
662 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
663 conn->info_ident = l2cap_get_ident(conn);
664
665 mod_timer(&conn->info_timer, jiffies +
666 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
667
668 l2cap_send_cmd(conn, conn->info_ident,
669 L2CAP_INFO_REQ, sizeof(req), &req);
670 }
671}
672
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300673static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
674{
675 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300676 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300677 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
678
679 switch (mode) {
680 case L2CAP_MODE_ERTM:
681 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
682 case L2CAP_MODE_STREAMING:
683 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
684 default:
685 return 0x00;
686 }
687}
688
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300689static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300690{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300691 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300692 struct l2cap_disconn_req req;
693
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300694 if (!conn)
695 return;
696
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300697 sk = chan->sk;
698
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300699 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300700 __clear_retrans_timer(chan);
701 __clear_monitor_timer(chan);
702 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300703 }
704
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300705 req.dcid = cpu_to_le16(chan->dcid);
706 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300707 l2cap_send_cmd(conn, l2cap_get_ident(conn),
708 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300709
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300710 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300711 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300712}
713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200715static void l2cap_conn_start(struct l2cap_conn *conn)
716{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300717 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200718
719 BT_DBG("conn %p", conn);
720
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300721 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200722
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300723 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300724 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300725
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200726 bh_lock_sock(sk);
727
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300728 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200729 bh_unlock_sock(sk);
730 continue;
731 }
732
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300733 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300734 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300735
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300736 if (!l2cap_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300737 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300738 bh_unlock_sock(sk);
739 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200740 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300741
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300742 if (!l2cap_mode_supported(chan->mode,
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300743 conn->feat_mask)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300744 && chan->conf_state &
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300745 L2CAP_CONF_STATE2_DEVICE) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300746 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300747 * so release the lock */
748 read_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300749 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300750 read_lock_bh(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300751 bh_unlock_sock(sk);
752 continue;
753 }
754
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300755 req.scid = cpu_to_le16(chan->scid);
756 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300757
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300758 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300759 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300760
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300761 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
762 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300763
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300764 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200765 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300766 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300767 rsp.scid = cpu_to_le16(chan->dcid);
768 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200769
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300770 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100771 if (bt_sk(sk)->defer_setup) {
772 struct sock *parent = bt_sk(sk)->parent;
773 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
774 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
775 parent->sk_data_ready(parent, 0);
776
777 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300778 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100779 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
780 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
781 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200782 } else {
783 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
784 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
785 }
786
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300787 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
788 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300789
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300790 if (chan->conf_state & L2CAP_CONF_REQ_SENT ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300791 rsp.result != L2CAP_CR_SUCCESS) {
792 bh_unlock_sock(sk);
793 continue;
794 }
795
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300796 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300797 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300798 l2cap_build_conf_req(chan, buf), buf);
799 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200800 }
801
802 bh_unlock_sock(sk);
803 }
804
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300805 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200806}
807
Ville Tervob62f3282011-02-10 22:38:50 -0300808/* Find socket with cid and source bdaddr.
809 * Returns closest match, locked.
810 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300811static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300812{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300813 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300814
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300815 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300816
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300817 list_for_each_entry(c, &chan_list, global_l) {
818 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300819
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300820 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300821 continue;
822
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300823 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300824 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300825 if (!bacmp(&bt_sk(sk)->src, src)) {
826 read_unlock(&chan_list_lock);
827 return c;
828 }
Ville Tervob62f3282011-02-10 22:38:50 -0300829
830 /* Closest match */
831 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300832 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300833 }
834 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300835
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300836 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300837
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300838 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300839}
840
841static void l2cap_le_conn_ready(struct l2cap_conn *conn)
842{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300843 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300844 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300845
846 BT_DBG("");
847
848 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300849 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300850 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300851 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300852 return;
853
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300854 parent = pchan->sk;
855
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300856 bh_lock_sock(parent);
857
Ville Tervob62f3282011-02-10 22:38:50 -0300858 /* Check for backlog size */
859 if (sk_acceptq_is_full(parent)) {
860 BT_DBG("backlog full %d", parent->sk_ack_backlog);
861 goto clean;
862 }
863
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300864 chan = pchan->ops->new_connection(pchan->data);
865 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300866 goto clean;
867
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300868 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300869
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300870 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300871
872 hci_conn_hold(conn->hcon);
873
Ville Tervob62f3282011-02-10 22:38:50 -0300874 bacpy(&bt_sk(sk)->src, conn->src);
875 bacpy(&bt_sk(sk)->dst, conn->dst);
876
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300877 bt_accept_enqueue(parent, sk);
878
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300879 __l2cap_chan_add(conn, chan);
880
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300881 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300882
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300883 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300884 parent->sk_data_ready(parent, 0);
885
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300886 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300887
888clean:
889 bh_unlock_sock(parent);
890}
891
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200892static void l2cap_conn_ready(struct l2cap_conn *conn)
893{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300894 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200895
896 BT_DBG("conn %p", conn);
897
Ville Tervob62f3282011-02-10 22:38:50 -0300898 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
899 l2cap_le_conn_ready(conn);
900
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300901 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200902
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300903 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300904 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300905
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200906 bh_lock_sock(sk);
907
Ville Tervoacd7d372011-02-10 22:38:49 -0300908 if (conn->hcon->type == LE_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300909 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300910 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervoacd7d372011-02-10 22:38:49 -0300911 sk->sk_state_change(sk);
912 }
913
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300914 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300915 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300916 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200917 sk->sk_state_change(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300918 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300919 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200920
921 bh_unlock_sock(sk);
922 }
923
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300924 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200925}
926
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200927/* Notify sockets that we cannot guaranty reliability anymore */
928static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
929{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300930 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200931
932 BT_DBG("conn %p", conn);
933
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300934 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200935
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300936 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300937 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300938
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300939 if (chan->force_reliable)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200940 sk->sk_err = err;
941 }
942
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300943 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200944}
945
946static void l2cap_info_timeout(unsigned long arg)
947{
948 struct l2cap_conn *conn = (void *) arg;
949
Marcel Holtmann984947d2009-02-06 23:35:19 +0100950 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100951 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100952
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200953 l2cap_conn_start(conn);
954}
955
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
957{
Marcel Holtmann01394182006-07-03 10:02:46 +0200958 struct l2cap_conn *conn = hcon->l2cap_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959
Marcel Holtmann01394182006-07-03 10:02:46 +0200960 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 return conn;
962
Marcel Holtmann01394182006-07-03 10:02:46 +0200963 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
964 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966
967 hcon->l2cap_data = conn;
968 conn->hcon = hcon;
969
Marcel Holtmann01394182006-07-03 10:02:46 +0200970 BT_DBG("hcon %p conn %p", hcon, conn);
971
Ville Tervoacd7d372011-02-10 22:38:49 -0300972 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
973 conn->mtu = hcon->hdev->le_mtu;
974 else
975 conn->mtu = hcon->hdev->acl_mtu;
976
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 conn->src = &hcon->hdev->bdaddr;
978 conn->dst = &hcon->dst;
979
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200980 conn->feat_mask = 0;
981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300983 rwlock_init(&conn->chan_lock);
984
985 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Ville Tervob62f3282011-02-10 22:38:50 -0300987 if (hcon->type != LE_LINK)
988 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +0000989 (unsigned long) conn);
990
Marcel Holtmann2950f212009-02-12 14:02:50 +0100991 conn->disc_reason = 0x13;
992
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 return conn;
994}
995
Marcel Holtmann01394182006-07-03 10:02:46 +0200996static void l2cap_conn_del(struct hci_conn *hcon, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997{
Marcel Holtmann01394182006-07-03 10:02:46 +0200998 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300999 struct l2cap_chan *chan, *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 struct sock *sk;
1001
Marcel Holtmann01394182006-07-03 10:02:46 +02001002 if (!conn)
1003 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1006
Wei Yongjun7585b972009-02-25 18:29:52 +08001007 kfree_skb(conn->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
1009 /* Kill channels */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001010 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001011 sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 bh_lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001013 l2cap_chan_del(chan, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 bh_unlock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03001015 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 }
1017
Dave Young8e8440f2008-03-03 12:18:55 -08001018 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
1019 del_timer_sync(&conn->info_timer);
Thomas Gleixner3ab22732008-02-26 17:42:56 -08001020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 hcon->l2cap_data = NULL;
1022 kfree(conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023}
1024
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001025static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001027 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001028 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001029 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030}
1031
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034/* Find socket with psm and source bdaddr.
1035 * Returns closest match.
1036 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001037static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001039 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001041 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001042
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001043 list_for_each_entry(c, &chan_list, global_l) {
1044 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001045
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001046 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 continue;
1048
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001049 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001051 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001052 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001053 return c;
1054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
1056 /* Closest match */
1057 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001058 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
1060 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001062 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001063
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001064 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065}
1066
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001067int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001069 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 bdaddr_t *src = &bt_sk(sk)->src;
1071 bdaddr_t *dst = &bt_sk(sk)->dst;
1072 struct l2cap_conn *conn;
1073 struct hci_conn *hcon;
1074 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001075 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001076 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001078 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001079 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001081 hdev = hci_get_route(dst, src);
1082 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 return -EHOSTUNREACH;
1084
1085 hci_dev_lock_bh(hdev);
1086
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001087 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001088
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001089 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001090 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001091 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001092 else
1093 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001094 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001095
Ville Tervo30e76272011-02-22 16:10:53 -03001096 if (IS_ERR(hcon)) {
1097 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001099 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101 conn = l2cap_conn_add(hcon, 0);
1102 if (!conn) {
1103 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001104 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 goto done;
1106 }
1107
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 /* Update source addr of the socket */
1109 bacpy(src, conn->src);
1110
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001111 l2cap_chan_add(conn, chan);
1112
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001113 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001114 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
1116 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001117 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001118 __clear_chan_timer(chan);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001119 if (l2cap_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001120 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001121 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001122 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 }
1124
Ville Tervo30e76272011-02-22 16:10:53 -03001125 err = 0;
1126
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127done:
1128 hci_dev_unlock_bh(hdev);
1129 hci_dev_put(hdev);
1130 return err;
1131}
1132
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001133int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001134{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001135 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001136 DECLARE_WAITQUEUE(wait, current);
1137 int err = 0;
1138 int timeo = HZ/5;
1139
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001140 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001141 while ((chan->unacked_frames > 0 && chan->conn)) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001142 set_current_state(TASK_INTERRUPTIBLE);
1143
1144 if (!timeo)
1145 timeo = HZ/5;
1146
1147 if (signal_pending(current)) {
1148 err = sock_intr_errno(timeo);
1149 break;
1150 }
1151
1152 release_sock(sk);
1153 timeo = schedule_timeout(timeo);
1154 lock_sock(sk);
1155
1156 err = sock_error(sk);
1157 if (err)
1158 break;
1159 }
1160 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001161 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001162 return err;
1163}
1164
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001165static void l2cap_monitor_timeout(unsigned long arg)
1166{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001167 struct l2cap_chan *chan = (void *) arg;
1168 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001169
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001170 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001171
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001172 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001173 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001174 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001175 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001176 return;
1177 }
1178
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001179 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001180 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001181
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001182 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001183 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001184}
1185
1186static void l2cap_retrans_timeout(unsigned long arg)
1187{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001188 struct l2cap_chan *chan = (void *) arg;
1189 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001190
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001191 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001192
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001193 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001194 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001195 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001196
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001197 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001198
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001199 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001200 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001201}
1202
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001203static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001204{
1205 struct sk_buff *skb;
1206
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001207 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001208 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001209 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001210 break;
1211
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001212 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001213 kfree_skb(skb);
1214
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001215 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001216 }
1217
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001218 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001219 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001220}
1221
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001222void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001223{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001224 struct hci_conn *hcon = chan->conn->hcon;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001225 u16 flags;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001226
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001227 BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001228
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001229 if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001230 flags = ACL_START_NO_FLUSH;
1231 else
1232 flags = ACL_START;
1233
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -07001234 bt_cb(skb)->force_active = chan->force_active;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001235 hci_send_acl(hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001236}
1237
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001238void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001239{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001240 struct sk_buff *skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001241 u16 control, fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001242
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001243 while ((skb = skb_dequeue(&chan->tx_q))) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001244 control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001245 control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001246 put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001247
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001248 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001249 fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
1250 put_unaligned_le16(fcs, skb->data + skb->len - 2);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001251 }
1252
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001253 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001254
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001255 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001256 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001257}
1258
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001259static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001260{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001261 struct sk_buff *skb, *tx_skb;
1262 u16 control, fcs;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001263
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001264 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001265 if (!skb)
1266 return;
1267
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001268 do {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001269 if (bt_cb(skb)->tx_seq == tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001270 break;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001271
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001272 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001273 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001274
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001275 } while ((skb = skb_queue_next(&chan->tx_q, skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001276
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001277 if (chan->remote_max_tx &&
1278 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001279 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001280 return;
1281 }
1282
1283 tx_skb = skb_clone(skb, GFP_ATOMIC);
1284 bt_cb(skb)->retries++;
1285 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Ruiyi Zhanga429b512011-04-18 11:04:30 +08001286 control &= L2CAP_CTRL_SAR;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001287
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001288 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001289 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001290 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001291 }
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001292
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001293 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001294 | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001295
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001296 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1297
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001298 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001299 fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
1300 put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
1301 }
1302
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001303 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001304}
1305
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001306int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001307{
1308 struct sk_buff *skb, *tx_skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001309 u16 control, fcs;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001310 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001311
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001312 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001313 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001314
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001315 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001316
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001317 if (chan->remote_max_tx &&
1318 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001319 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001320 break;
1321 }
1322
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001323 tx_skb = skb_clone(skb, GFP_ATOMIC);
1324
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001325 bt_cb(skb)->retries++;
1326
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001327 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001328 control &= L2CAP_CTRL_SAR;
1329
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001330 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001331 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001332 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001333 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001334 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
1335 | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001336 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1337
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001338
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001339 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001340 fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
1341 put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
1342 }
1343
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001344 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001345
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001346 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001347
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001348 bt_cb(skb)->tx_seq = chan->next_tx_seq;
1349 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001350
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301351 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001352 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301353
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001354 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001355
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001356 if (skb_queue_is_last(&chan->tx_q, skb))
1357 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001358 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001359 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001360
1361 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001362 }
1363
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001364 return nsent;
1365}
1366
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001367static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001368{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001369 int ret;
1370
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001371 if (!skb_queue_empty(&chan->tx_q))
1372 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001373
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001374 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001375 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001376 return ret;
1377}
1378
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001379static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001380{
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001381 u16 control = 0;
1382
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001383 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001384
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001385 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001386 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001387 chan->conn_state |= L2CAP_CONN_RNR_SENT;
1388 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001389 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001390 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001391
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001392 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001393 return;
1394
1395 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001396 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001397}
1398
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001399static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001400{
1401 struct srej_list *tail;
1402 u16 control;
1403
1404 control = L2CAP_SUPER_SELECT_REJECT;
1405 control |= L2CAP_CTRL_FINAL;
1406
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001407 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001408 control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
1409
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001410 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001411}
1412
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001413static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001415 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001416 struct sk_buff **frag;
1417 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001419 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001420 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
1422 sent += count;
1423 len -= count;
1424
1425 /* Continuation fragments (no L2CAP header) */
1426 frag = &skb_shinfo(skb)->frag_list;
1427 while (len) {
1428 count = min_t(unsigned int, conn->mtu, len);
1429
1430 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1431 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001432 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001433 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1434 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
1436 sent += count;
1437 len -= count;
1438
1439 frag = &(*frag)->next;
1440 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001441
1442 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001443}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001445struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001446{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001447 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001448 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001449 struct sk_buff *skb;
1450 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1451 struct l2cap_hdr *lh;
1452
1453 BT_DBG("sk %p len %d", sk, (int)len);
1454
1455 count = min_t(unsigned int, (conn->mtu - hlen), len);
1456 skb = bt_skb_send_alloc(sk, count + hlen,
1457 msg->msg_flags & MSG_DONTWAIT, &err);
1458 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001459 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001460
1461 /* Create L2CAP header */
1462 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001463 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001464 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001465 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001466
1467 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1468 if (unlikely(err < 0)) {
1469 kfree_skb(skb);
1470 return ERR_PTR(err);
1471 }
1472 return skb;
1473}
1474
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001475struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001476{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001477 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001478 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001479 struct sk_buff *skb;
1480 int err, count, hlen = L2CAP_HDR_SIZE;
1481 struct l2cap_hdr *lh;
1482
1483 BT_DBG("sk %p len %d", sk, (int)len);
1484
1485 count = min_t(unsigned int, (conn->mtu - hlen), len);
1486 skb = bt_skb_send_alloc(sk, count + hlen,
1487 msg->msg_flags & MSG_DONTWAIT, &err);
1488 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001489 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001490
1491 /* Create L2CAP header */
1492 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001493 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001494 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1495
1496 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1497 if (unlikely(err < 0)) {
1498 kfree_skb(skb);
1499 return ERR_PTR(err);
1500 }
1501 return skb;
1502}
1503
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001504struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001505{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001506 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001507 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001508 struct sk_buff *skb;
1509 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1510 struct l2cap_hdr *lh;
1511
1512 BT_DBG("sk %p len %d", sk, (int)len);
1513
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001514 if (!conn)
1515 return ERR_PTR(-ENOTCONN);
1516
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001517 if (sdulen)
1518 hlen += 2;
1519
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001520 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001521 hlen += 2;
1522
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001523 count = min_t(unsigned int, (conn->mtu - hlen), len);
1524 skb = bt_skb_send_alloc(sk, count + hlen,
1525 msg->msg_flags & MSG_DONTWAIT, &err);
1526 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001527 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001528
1529 /* Create L2CAP header */
1530 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001531 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001532 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1533 put_unaligned_le16(control, skb_put(skb, 2));
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001534 if (sdulen)
1535 put_unaligned_le16(sdulen, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001536
1537 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1538 if (unlikely(err < 0)) {
1539 kfree_skb(skb);
1540 return ERR_PTR(err);
1541 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001542
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001543 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001544 put_unaligned_le16(0, skb_put(skb, 2));
1545
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001546 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001547 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548}
1549
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001550int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001551{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001552 struct sk_buff *skb;
1553 struct sk_buff_head sar_queue;
1554 u16 control;
1555 size_t size = 0;
1556
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001557 skb_queue_head_init(&sar_queue);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001558 control = L2CAP_SDU_START;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001559 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001560 if (IS_ERR(skb))
1561 return PTR_ERR(skb);
1562
1563 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001564 len -= chan->remote_mps;
1565 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001566
1567 while (len > 0) {
1568 size_t buflen;
1569
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001570 if (len > chan->remote_mps) {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001571 control = L2CAP_SDU_CONTINUE;
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001572 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001573 } else {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001574 control = L2CAP_SDU_END;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001575 buflen = len;
1576 }
1577
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001578 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001579 if (IS_ERR(skb)) {
1580 skb_queue_purge(&sar_queue);
1581 return PTR_ERR(skb);
1582 }
1583
1584 __skb_queue_tail(&sar_queue, skb);
1585 len -= buflen;
1586 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001587 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001588 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1589 if (chan->tx_send_head == NULL)
1590 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001591
1592 return size;
1593}
1594
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001595int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
1596{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001597 struct sk_buff *skb;
1598 u16 control;
1599 int err;
1600
1601 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001602 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001603 skb = l2cap_create_connless_pdu(chan, msg, len);
1604 if (IS_ERR(skb))
1605 return PTR_ERR(skb);
1606
1607 l2cap_do_send(chan, skb);
1608 return len;
1609 }
1610
1611 switch (chan->mode) {
1612 case L2CAP_MODE_BASIC:
1613 /* Check outgoing MTU */
1614 if (len > chan->omtu)
1615 return -EMSGSIZE;
1616
1617 /* Create a basic PDU */
1618 skb = l2cap_create_basic_pdu(chan, msg, len);
1619 if (IS_ERR(skb))
1620 return PTR_ERR(skb);
1621
1622 l2cap_do_send(chan, skb);
1623 err = len;
1624 break;
1625
1626 case L2CAP_MODE_ERTM:
1627 case L2CAP_MODE_STREAMING:
1628 /* Entire SDU fits into one PDU */
1629 if (len <= chan->remote_mps) {
1630 control = L2CAP_SDU_UNSEGMENTED;
1631 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1632 0);
1633 if (IS_ERR(skb))
1634 return PTR_ERR(skb);
1635
1636 __skb_queue_tail(&chan->tx_q, skb);
1637
1638 if (chan->tx_send_head == NULL)
1639 chan->tx_send_head = skb;
1640
1641 } else {
1642 /* Segment SDU into multiples PDUs */
1643 err = l2cap_sar_segment_sdu(chan, msg, len);
1644 if (err < 0)
1645 return err;
1646 }
1647
1648 if (chan->mode == L2CAP_MODE_STREAMING) {
1649 l2cap_streaming_send(chan);
1650 err = len;
1651 break;
1652 }
1653
1654 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
1655 (chan->conn_state & L2CAP_CONN_WAIT_F)) {
1656 err = len;
1657 break;
1658 }
1659
1660 err = l2cap_ertm_send(chan);
1661 if (err >= 0)
1662 err = len;
1663
1664 break;
1665
1666 default:
1667 BT_DBG("bad state %1.1x", chan->mode);
1668 err = -EBADFD;
1669 }
1670
1671 return err;
1672}
1673
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674static void l2cap_chan_ready(struct sock *sk)
1675{
1676 struct sock *parent = bt_sk(sk)->parent;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001677 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678
1679 BT_DBG("sk %p, parent %p", sk, parent);
1680
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001681 chan->conf_state = 0;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001682 __clear_chan_timer(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
1684 if (!parent) {
1685 /* Outgoing channel.
1686 * Wake up socket sleeping on connect.
1687 */
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001688 l2cap_state_change(chan, BT_CONNECTED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 sk->sk_state_change(sk);
1690 } else {
1691 /* Incoming channel.
1692 * Wake up socket sleeping on accept.
1693 */
1694 parent->sk_data_ready(parent, 0);
1695 }
1696}
1697
1698/* Copy frame to all raw sockets on that connection */
1699static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1700{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001702 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703
1704 BT_DBG("conn %p", conn);
1705
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001706 read_lock(&conn->chan_lock);
1707 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001708 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001709 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 continue;
1711
1712 /* Don't send frame to the socket it came from */
1713 if (skb->sk == sk)
1714 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001715 nskb = skb_clone(skb, GFP_ATOMIC);
1716 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 continue;
1718
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001719 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 kfree_skb(nskb);
1721 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001722 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723}
1724
1725/* ---- L2CAP signalling commands ---- */
1726static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1727 u8 code, u8 ident, u16 dlen, void *data)
1728{
1729 struct sk_buff *skb, **frag;
1730 struct l2cap_cmd_hdr *cmd;
1731 struct l2cap_hdr *lh;
1732 int len, count;
1733
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001734 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1735 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736
1737 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1738 count = min_t(unsigned int, conn->mtu, len);
1739
1740 skb = bt_skb_alloc(count, GFP_ATOMIC);
1741 if (!skb)
1742 return NULL;
1743
1744 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001745 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001746
1747 if (conn->hcon->type == LE_LINK)
1748 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1749 else
1750 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
1752 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1753 cmd->code = code;
1754 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001755 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756
1757 if (dlen) {
1758 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1759 memcpy(skb_put(skb, count), data, count);
1760 data += count;
1761 }
1762
1763 len -= skb->len;
1764
1765 /* Continuation fragments (no L2CAP header) */
1766 frag = &skb_shinfo(skb)->frag_list;
1767 while (len) {
1768 count = min_t(unsigned int, conn->mtu, len);
1769
1770 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1771 if (!*frag)
1772 goto fail;
1773
1774 memcpy(skb_put(*frag, count), data, count);
1775
1776 len -= count;
1777 data += count;
1778
1779 frag = &(*frag)->next;
1780 }
1781
1782 return skb;
1783
1784fail:
1785 kfree_skb(skb);
1786 return NULL;
1787}
1788
1789static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1790{
1791 struct l2cap_conf_opt *opt = *ptr;
1792 int len;
1793
1794 len = L2CAP_CONF_OPT_SIZE + opt->len;
1795 *ptr += len;
1796
1797 *type = opt->type;
1798 *olen = opt->len;
1799
1800 switch (opt->len) {
1801 case 1:
1802 *val = *((u8 *) opt->val);
1803 break;
1804
1805 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001806 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 break;
1808
1809 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001810 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 break;
1812
1813 default:
1814 *val = (unsigned long) opt->val;
1815 break;
1816 }
1817
1818 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1819 return len;
1820}
1821
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1823{
1824 struct l2cap_conf_opt *opt = *ptr;
1825
1826 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1827
1828 opt->type = type;
1829 opt->len = len;
1830
1831 switch (len) {
1832 case 1:
1833 *((u8 *) opt->val) = val;
1834 break;
1835
1836 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001837 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 break;
1839
1840 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001841 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 break;
1843
1844 default:
1845 memcpy(opt->val, (void *) val, len);
1846 break;
1847 }
1848
1849 *ptr += L2CAP_CONF_OPT_SIZE + len;
1850}
1851
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001852static void l2cap_ack_timeout(unsigned long arg)
1853{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001854 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001855
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001856 bh_lock_sock(chan->sk);
1857 l2cap_send_ack(chan);
1858 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001859}
1860
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001861static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001862{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001863 struct sock *sk = chan->sk;
1864
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001865 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001866 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001867 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001868 chan->num_acked = 0;
1869 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001870
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001871 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1872 (unsigned long) chan);
1873 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1874 (unsigned long) chan);
1875 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001876
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001877 skb_queue_head_init(&chan->srej_q);
1878 skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001879
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001880 INIT_LIST_HEAD(&chan->srej_l);
1881
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03001882 INIT_WORK(&chan->busy_work, l2cap_busy_work);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001883
1884 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001885}
1886
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001887static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1888{
1889 switch (mode) {
1890 case L2CAP_MODE_STREAMING:
1891 case L2CAP_MODE_ERTM:
1892 if (l2cap_mode_supported(mode, remote_feat_mask))
1893 return mode;
1894 /* fall through */
1895 default:
1896 return L2CAP_MODE_BASIC;
1897 }
1898}
1899
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03001900static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001903 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 void *ptr = req->data;
1905
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001906 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001908 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001909 goto done;
1910
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001911 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001912 case L2CAP_MODE_STREAMING:
1913 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001914 if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001915 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001916
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03001917 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001918 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001919 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001920 break;
1921 }
1922
1923done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001924 if (chan->imtu != L2CAP_DEFAULT_MTU)
1925 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02001926
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001927 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001928 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001929 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
1930 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001931 break;
1932
Gustavo F. Padovan62547752010-06-08 20:05:31 -03001933 rfc.mode = L2CAP_MODE_BASIC;
1934 rfc.txwin_size = 0;
1935 rfc.max_transmit = 0;
1936 rfc.retrans_timeout = 0;
1937 rfc.monitor_timeout = 0;
1938 rfc.max_pdu_size = 0;
1939
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001940 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1941 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001942 break;
1943
1944 case L2CAP_MODE_ERTM:
1945 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001946 rfc.txwin_size = chan->tx_win;
1947 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001948 rfc.retrans_timeout = 0;
1949 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001950 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001951 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1952 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001953
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001954 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1955 (unsigned long) &rfc);
1956
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001957 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001958 break;
1959
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001960 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001961 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001962 chan->fcs = L2CAP_FCS_NONE;
1963 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001964 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001965 break;
1966
1967 case L2CAP_MODE_STREAMING:
1968 rfc.mode = L2CAP_MODE_STREAMING;
1969 rfc.txwin_size = 0;
1970 rfc.max_transmit = 0;
1971 rfc.retrans_timeout = 0;
1972 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001973 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001974 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1975 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001976
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001977 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1978 (unsigned long) &rfc);
1979
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001980 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001981 break;
1982
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001983 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001984 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001985 chan->fcs = L2CAP_FCS_NONE;
1986 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001987 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001988 break;
1989 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001991 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001992 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993
1994 return ptr - data;
1995}
1996
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001997static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001999 struct l2cap_conf_rsp *rsp = data;
2000 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002001 void *req = chan->conf_req;
2002 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002003 int type, hint, olen;
2004 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002005 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Marcel Holtmann861d6882007-10-20 13:37:06 +02002006 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002007 u16 result = L2CAP_CONF_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002009 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002010
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002011 while (len >= L2CAP_CONF_OPT_SIZE) {
2012 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002014 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002015 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002016
2017 switch (type) {
2018 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002019 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002020 break;
2021
2022 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002023 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002024 break;
2025
2026 case L2CAP_CONF_QOS:
2027 break;
2028
Marcel Holtmann6464f352007-10-20 13:39:51 +02002029 case L2CAP_CONF_RFC:
2030 if (olen == sizeof(rfc))
2031 memcpy(&rfc, (void *) val, olen);
2032 break;
2033
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002034 case L2CAP_CONF_FCS:
2035 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002036 chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002037
2038 break;
2039
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002040 default:
2041 if (hint)
2042 break;
2043
2044 result = L2CAP_CONF_UNKNOWN;
2045 *((u8 *) ptr++) = type;
2046 break;
2047 }
2048 }
2049
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002050 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002051 goto done;
2052
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002053 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002054 case L2CAP_MODE_STREAMING:
2055 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002056 if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002057 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002058 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002059 break;
2060 }
2061
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002062 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002063 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002064
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002065 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002066 }
2067
2068done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002069 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002070 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002071 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002072
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002073 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002074 return -ECONNREFUSED;
2075
2076 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2077 sizeof(rfc), (unsigned long) &rfc);
2078 }
2079
2080
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002081 if (result == L2CAP_CONF_SUCCESS) {
2082 /* Configure output options and let the other side know
2083 * which ones we don't like. */
2084
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002085 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2086 result = L2CAP_CONF_UNACCEPT;
2087 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002088 chan->omtu = mtu;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002089 chan->conf_state |= L2CAP_CONF_MTU_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002090 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002091 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002092
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002093 switch (rfc.mode) {
2094 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002095 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002096 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002097 break;
2098
2099 case L2CAP_MODE_ERTM:
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002100 chan->remote_tx_win = rfc.txwin_size;
2101 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002102
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002103 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2104 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002105
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002106 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002107
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002108 rfc.retrans_timeout =
2109 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2110 rfc.monitor_timeout =
2111 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002112
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002113 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002114
2115 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2116 sizeof(rfc), (unsigned long) &rfc);
2117
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002118 break;
2119
2120 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002121 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2122 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002123
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002124 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002125
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002126 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002127
2128 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2129 sizeof(rfc), (unsigned long) &rfc);
2130
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002131 break;
2132
2133 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002134 result = L2CAP_CONF_UNACCEPT;
2135
2136 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002137 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002138 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002139
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002140 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002141 chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002142 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002143 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002144 rsp->result = cpu_to_le16(result);
2145 rsp->flags = cpu_to_le16(0x0000);
2146
2147 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002148}
2149
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002150static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002151{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002152 struct l2cap_conf_req *req = data;
2153 void *ptr = req->data;
2154 int type, olen;
2155 unsigned long val;
2156 struct l2cap_conf_rfc rfc;
2157
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002158 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002159
2160 while (len >= L2CAP_CONF_OPT_SIZE) {
2161 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2162
2163 switch (type) {
2164 case L2CAP_CONF_MTU:
2165 if (val < L2CAP_DEFAULT_MIN_MTU) {
2166 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002167 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002168 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002169 chan->imtu = val;
2170 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002171 break;
2172
2173 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002174 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002175 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002176 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002177 break;
2178
2179 case L2CAP_CONF_RFC:
2180 if (olen == sizeof(rfc))
2181 memcpy(&rfc, (void *)val, olen);
2182
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002183 if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002184 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002185 return -ECONNREFUSED;
2186
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002187 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002188
2189 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2190 sizeof(rfc), (unsigned long) &rfc);
2191 break;
2192 }
2193 }
2194
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002195 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002196 return -ECONNREFUSED;
2197
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002198 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002199
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002200 if (*result == L2CAP_CONF_SUCCESS) {
2201 switch (rfc.mode) {
2202 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002203 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2204 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2205 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002206 break;
2207 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002208 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002209 }
2210 }
2211
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002212 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002213 req->flags = cpu_to_le16(0x0000);
2214
2215 return ptr - data;
2216}
2217
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002218static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219{
2220 struct l2cap_conf_rsp *rsp = data;
2221 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002223 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002225 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002226 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002227 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
2229 return ptr - data;
2230}
2231
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002232void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002233{
2234 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002235 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002236 u8 buf[128];
2237
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002238 rsp.scid = cpu_to_le16(chan->dcid);
2239 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002240 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2241 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2242 l2cap_send_cmd(conn, chan->ident,
2243 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2244
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002245 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002246 return;
2247
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002248 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002249 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2250 l2cap_build_conf_req(chan, buf), buf);
2251 chan->num_conf_req++;
2252}
2253
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002254static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002255{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002256 int type, olen;
2257 unsigned long val;
2258 struct l2cap_conf_rfc rfc;
2259
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002260 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002261
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002262 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002263 return;
2264
2265 while (len >= L2CAP_CONF_OPT_SIZE) {
2266 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2267
2268 switch (type) {
2269 case L2CAP_CONF_RFC:
2270 if (olen == sizeof(rfc))
2271 memcpy(&rfc, (void *)val, olen);
2272 goto done;
2273 }
2274 }
2275
2276done:
2277 switch (rfc.mode) {
2278 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002279 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2280 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2281 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002282 break;
2283 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002284 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002285 }
2286}
2287
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002288static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2289{
2290 struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
2291
2292 if (rej->reason != 0x0000)
2293 return 0;
2294
2295 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2296 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002297 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002298
2299 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002300 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002301
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002302 l2cap_conn_start(conn);
2303 }
2304
2305 return 0;
2306}
2307
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2309{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2311 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002312 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002313 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002314 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
2316 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002317 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002318
2319 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2320
2321 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002322 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2323 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324 result = L2CAP_CR_BAD_PSM;
2325 goto sendresp;
2326 }
2327
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002328 parent = pchan->sk;
2329
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002330 bh_lock_sock(parent);
2331
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002332 /* Check if the ACL is secure enough (if not SDP) */
2333 if (psm != cpu_to_le16(0x0001) &&
2334 !hci_conn_check_link_mode(conn->hcon)) {
Marcel Holtmann2950f212009-02-12 14:02:50 +01002335 conn->disc_reason = 0x05;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002336 result = L2CAP_CR_SEC_BLOCK;
2337 goto response;
2338 }
2339
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 result = L2CAP_CR_NO_MEM;
2341
2342 /* Check for backlog size */
2343 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002344 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 goto response;
2346 }
2347
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002348 chan = pchan->ops->new_connection(pchan->data);
2349 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350 goto response;
2351
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002352 sk = chan->sk;
2353
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002354 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355
2356 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002357 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2358 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002360 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 goto response;
2362 }
2363
2364 hci_conn_hold(conn->hcon);
2365
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366 bacpy(&bt_sk(sk)->src, conn->src);
2367 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002368 chan->psm = psm;
2369 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002371 bt_accept_enqueue(parent, sk);
2372
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002373 __l2cap_chan_add(conn, chan);
2374
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002375 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002377 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002379 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380
Marcel Holtmann984947d2009-02-06 23:35:19 +01002381 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03002382 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002383 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002384 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002385 result = L2CAP_CR_PEND;
2386 status = L2CAP_CS_AUTHOR_PEND;
2387 parent->sk_data_ready(parent, 0);
2388 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002389 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002390 result = L2CAP_CR_SUCCESS;
2391 status = L2CAP_CS_NO_INFO;
2392 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002393 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002394 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002395 result = L2CAP_CR_PEND;
2396 status = L2CAP_CS_AUTHEN_PEND;
2397 }
2398 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002399 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002400 result = L2CAP_CR_PEND;
2401 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 }
2403
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002404 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405
2406response:
2407 bh_unlock_sock(parent);
2408
2409sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002410 rsp.scid = cpu_to_le16(scid);
2411 rsp.dcid = cpu_to_le16(dcid);
2412 rsp.result = cpu_to_le16(result);
2413 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002415
2416 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2417 struct l2cap_info_req info;
2418 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2419
2420 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2421 conn->info_ident = l2cap_get_ident(conn);
2422
2423 mod_timer(&conn->info_timer, jiffies +
2424 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2425
2426 l2cap_send_cmd(conn, conn->info_ident,
2427 L2CAP_INFO_REQ, sizeof(info), &info);
2428 }
2429
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002430 if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002431 result == L2CAP_CR_SUCCESS) {
2432 u8 buf[128];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002433 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002434 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002435 l2cap_build_conf_req(chan, buf), buf);
2436 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002437 }
2438
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 return 0;
2440}
2441
2442static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2443{
2444 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2445 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002446 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 struct sock *sk;
2448 u8 req[128];
2449
2450 scid = __le16_to_cpu(rsp->scid);
2451 dcid = __le16_to_cpu(rsp->dcid);
2452 result = __le16_to_cpu(rsp->result);
2453 status = __le16_to_cpu(rsp->status);
2454
2455 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2456
2457 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002458 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002459 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002460 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002461 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002462 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002463 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002464 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 }
2466
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002467 sk = chan->sk;
2468
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 switch (result) {
2470 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002471 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002472 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002473 chan->dcid = dcid;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002474 chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002475
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002476 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002477 break;
2478
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002479 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002480
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002482 l2cap_build_conf_req(chan, req), req);
2483 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 break;
2485
2486 case L2CAP_CR_PEND:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002487 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 break;
2489
2490 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002491 /* don't delete l2cap channel if sk is owned by user */
2492 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002493 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002494 __clear_chan_timer(chan);
2495 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002496 break;
2497 }
2498
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002499 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 break;
2501 }
2502
2503 bh_unlock_sock(sk);
2504 return 0;
2505}
2506
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002507static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002508{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002509 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
2510
Mat Martineau8c462b62010-08-24 15:35:42 -07002511 /* FCS is enabled only in ERTM or streaming mode, if one or both
2512 * sides request it.
2513 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002514 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002515 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002516 else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002517 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002518}
2519
Al Viro88219a02007-07-29 00:17:25 -07002520static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521{
2522 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2523 u16 dcid, flags;
2524 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002525 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002526 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002527 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528
2529 dcid = __le16_to_cpu(req->dcid);
2530 flags = __le16_to_cpu(req->flags);
2531
2532 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2533
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002534 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002535 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 return -ENOENT;
2537
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002538 sk = chan->sk;
2539
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002540 if (chan->state != BT_CONFIG) {
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002541 struct l2cap_cmd_rej rej;
2542
2543 rej.reason = cpu_to_le16(0x0002);
2544 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2545 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002546 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002547 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002548
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002549 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002550 len = cmd_len - sizeof(*req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002551 if (chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002552 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002553 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002554 L2CAP_CONF_REJECT, flags), rsp);
2555 goto unlock;
2556 }
2557
2558 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002559 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2560 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561
2562 if (flags & 0x0001) {
2563 /* Incomplete config. Send empty response. */
2564 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002565 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002566 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 goto unlock;
2568 }
2569
2570 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002571 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002572 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002573 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002575 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002577 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002578 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002579
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002580 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002581 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002582
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002583 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002584 goto unlock;
2585
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002586 if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002587 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002588
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002589 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002590
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002591 chan->next_tx_seq = 0;
2592 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002593 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002594 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002595 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002596
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002598 goto unlock;
2599 }
2600
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002601 if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002602 u8 buf[64];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002603 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002605 l2cap_build_conf_req(chan, buf), buf);
2606 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 }
2608
2609unlock:
2610 bh_unlock_sock(sk);
2611 return 0;
2612}
2613
2614static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2615{
2616 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2617 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002618 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002620 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
2622 scid = __le16_to_cpu(rsp->scid);
2623 flags = __le16_to_cpu(rsp->flags);
2624 result = __le16_to_cpu(rsp->result);
2625
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002626 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2627 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002629 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002630 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 return 0;
2632
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002633 sk = chan->sk;
2634
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 switch (result) {
2636 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002637 l2cap_conf_rfc_get(chan, rsp->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 break;
2639
2640 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002641 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002642 char req[64];
2643
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002644 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002645 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002646 goto done;
2647 }
2648
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002649 /* throw out any old stored conf requests */
2650 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002651 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2652 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002653 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002654 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002655 goto done;
2656 }
2657
2658 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2659 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002660 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002661 if (result != L2CAP_CONF_SUCCESS)
2662 goto done;
2663 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 }
2665
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002666 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002667 sk->sk_err = ECONNRESET;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002668 __set_chan_timer(chan, HZ * 5);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002669 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 goto done;
2671 }
2672
2673 if (flags & 0x01)
2674 goto done;
2675
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002676 chan->conf_state |= L2CAP_CONF_INPUT_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002678 if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002679 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002680
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002681 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002682 chan->next_tx_seq = 0;
2683 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002684 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002685 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002686 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002687
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 l2cap_chan_ready(sk);
2689 }
2690
2691done:
2692 bh_unlock_sock(sk);
2693 return 0;
2694}
2695
2696static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2697{
2698 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2699 struct l2cap_disconn_rsp rsp;
2700 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002701 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 struct sock *sk;
2703
2704 scid = __le16_to_cpu(req->scid);
2705 dcid = __le16_to_cpu(req->dcid);
2706
2707 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2708
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002709 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002710 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 return 0;
2712
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002713 sk = chan->sk;
2714
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002715 rsp.dcid = cpu_to_le16(chan->scid);
2716 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2718
2719 sk->sk_shutdown = SHUTDOWN_MASK;
2720
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002721 /* don't delete l2cap channel if sk is owned by user */
2722 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002723 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002724 __clear_chan_timer(chan);
2725 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002726 bh_unlock_sock(sk);
2727 return 0;
2728 }
2729
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002730 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 bh_unlock_sock(sk);
2732
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002733 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 return 0;
2735}
2736
2737static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2738{
2739 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
2740 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002741 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 struct sock *sk;
2743
2744 scid = __le16_to_cpu(rsp->scid);
2745 dcid = __le16_to_cpu(rsp->dcid);
2746
2747 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
2748
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002749 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002750 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 return 0;
2752
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002753 sk = chan->sk;
2754
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002755 /* don't delete l2cap channel if sk is owned by user */
2756 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002757 l2cap_state_change(chan,BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002758 __clear_chan_timer(chan);
2759 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002760 bh_unlock_sock(sk);
2761 return 0;
2762 }
2763
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002764 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 bh_unlock_sock(sk);
2766
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002767 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 return 0;
2769}
2770
2771static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2772{
2773 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 u16 type;
2775
2776 type = __le16_to_cpu(req->type);
2777
2778 BT_DBG("type 0x%4.4x", type);
2779
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002780 if (type == L2CAP_IT_FEAT_MASK) {
2781 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07002782 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002783 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2784 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2785 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03002786 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002787 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
2788 | L2CAP_FEAT_FCS;
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03002789 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002790 l2cap_send_cmd(conn, cmd->ident,
2791 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002792 } else if (type == L2CAP_IT_FIXED_CHAN) {
2793 u8 buf[12];
2794 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2795 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2796 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
2797 memcpy(buf + 4, l2cap_fixed_chan, 8);
2798 l2cap_send_cmd(conn, cmd->ident,
2799 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002800 } else {
2801 struct l2cap_info_rsp rsp;
2802 rsp.type = cpu_to_le16(type);
2803 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
2804 l2cap_send_cmd(conn, cmd->ident,
2805 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
2806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
2808 return 0;
2809}
2810
2811static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2812{
2813 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
2814 u16 type, result;
2815
2816 type = __le16_to_cpu(rsp->type);
2817 result = __le16_to_cpu(rsp->result);
2818
2819 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
2820
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02002821 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
2822 if (cmd->ident != conn->info_ident ||
2823 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
2824 return 0;
2825
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002826 del_timer(&conn->info_timer);
2827
Ville Tervoadb08ed2010-08-04 09:43:33 +03002828 if (result != L2CAP_IR_SUCCESS) {
2829 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2830 conn->info_ident = 0;
2831
2832 l2cap_conn_start(conn);
2833
2834 return 0;
2835 }
2836
Marcel Holtmann984947d2009-02-06 23:35:19 +01002837 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07002838 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002839
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002840 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002841 struct l2cap_info_req req;
2842 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2843
2844 conn->info_ident = l2cap_get_ident(conn);
2845
2846 l2cap_send_cmd(conn, conn->info_ident,
2847 L2CAP_INFO_REQ, sizeof(req), &req);
2848 } else {
2849 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2850 conn->info_ident = 0;
2851
2852 l2cap_conn_start(conn);
2853 }
2854 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01002855 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002856 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002857
2858 l2cap_conn_start(conn);
2859 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002860
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 return 0;
2862}
2863
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002864static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02002865 u16 to_multiplier)
2866{
2867 u16 max_latency;
2868
2869 if (min > max || min < 6 || max > 3200)
2870 return -EINVAL;
2871
2872 if (to_multiplier < 10 || to_multiplier > 3200)
2873 return -EINVAL;
2874
2875 if (max >= to_multiplier * 8)
2876 return -EINVAL;
2877
2878 max_latency = (to_multiplier * 8 / max) - 1;
2879 if (latency > 499 || latency > max_latency)
2880 return -EINVAL;
2881
2882 return 0;
2883}
2884
2885static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
2886 struct l2cap_cmd_hdr *cmd, u8 *data)
2887{
2888 struct hci_conn *hcon = conn->hcon;
2889 struct l2cap_conn_param_update_req *req;
2890 struct l2cap_conn_param_update_rsp rsp;
2891 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002892 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02002893
2894 if (!(hcon->link_mode & HCI_LM_MASTER))
2895 return -EINVAL;
2896
2897 cmd_len = __le16_to_cpu(cmd->len);
2898 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
2899 return -EPROTO;
2900
2901 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002902 min = __le16_to_cpu(req->min);
2903 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02002904 latency = __le16_to_cpu(req->latency);
2905 to_multiplier = __le16_to_cpu(req->to_multiplier);
2906
2907 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
2908 min, max, latency, to_multiplier);
2909
2910 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002911
2912 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
2913 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02002914 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
2915 else
2916 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
2917
2918 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
2919 sizeof(rsp), &rsp);
2920
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002921 if (!err)
2922 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
2923
Claudio Takahaside731152011-02-11 19:28:55 -02002924 return 0;
2925}
2926
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002927static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
2928 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
2929{
2930 int err = 0;
2931
2932 switch (cmd->code) {
2933 case L2CAP_COMMAND_REJ:
2934 l2cap_command_rej(conn, cmd, data);
2935 break;
2936
2937 case L2CAP_CONN_REQ:
2938 err = l2cap_connect_req(conn, cmd, data);
2939 break;
2940
2941 case L2CAP_CONN_RSP:
2942 err = l2cap_connect_rsp(conn, cmd, data);
2943 break;
2944
2945 case L2CAP_CONF_REQ:
2946 err = l2cap_config_req(conn, cmd, cmd_len, data);
2947 break;
2948
2949 case L2CAP_CONF_RSP:
2950 err = l2cap_config_rsp(conn, cmd, data);
2951 break;
2952
2953 case L2CAP_DISCONN_REQ:
2954 err = l2cap_disconnect_req(conn, cmd, data);
2955 break;
2956
2957 case L2CAP_DISCONN_RSP:
2958 err = l2cap_disconnect_rsp(conn, cmd, data);
2959 break;
2960
2961 case L2CAP_ECHO_REQ:
2962 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
2963 break;
2964
2965 case L2CAP_ECHO_RSP:
2966 break;
2967
2968 case L2CAP_INFO_REQ:
2969 err = l2cap_information_req(conn, cmd, data);
2970 break;
2971
2972 case L2CAP_INFO_RSP:
2973 err = l2cap_information_rsp(conn, cmd, data);
2974 break;
2975
2976 default:
2977 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
2978 err = -EINVAL;
2979 break;
2980 }
2981
2982 return err;
2983}
2984
2985static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
2986 struct l2cap_cmd_hdr *cmd, u8 *data)
2987{
2988 switch (cmd->code) {
2989 case L2CAP_COMMAND_REJ:
2990 return 0;
2991
2992 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02002993 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002994
2995 case L2CAP_CONN_PARAM_UPDATE_RSP:
2996 return 0;
2997
2998 default:
2999 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3000 return -EINVAL;
3001 }
3002}
3003
3004static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3005 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006{
3007 u8 *data = skb->data;
3008 int len = skb->len;
3009 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003010 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011
3012 l2cap_raw_recv(conn, skb);
3013
3014 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003015 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3017 data += L2CAP_CMD_HDR_SIZE;
3018 len -= L2CAP_CMD_HDR_SIZE;
3019
Al Viro88219a02007-07-29 00:17:25 -07003020 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021
Al Viro88219a02007-07-29 00:17:25 -07003022 BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len, cmd.ident);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003023
Al Viro88219a02007-07-29 00:17:25 -07003024 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 BT_DBG("corrupted command");
3026 break;
3027 }
3028
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003029 if (conn->hcon->type == LE_LINK)
3030 err = l2cap_le_sig_cmd(conn, &cmd, data);
3031 else
3032 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033
3034 if (err) {
3035 struct l2cap_cmd_rej rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003036
3037 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
3039 /* FIXME: Map err to a valid reason */
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07003040 rej.reason = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3042 }
3043
Al Viro88219a02007-07-29 00:17:25 -07003044 data += cmd_len;
3045 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 }
3047
3048 kfree_skb(skb);
3049}
3050
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003051static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003052{
3053 u16 our_fcs, rcv_fcs;
3054 int hdr_size = L2CAP_HDR_SIZE + 2;
3055
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003056 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003057 skb_trim(skb, skb->len - 2);
3058 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3059 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3060
3061 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003062 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003063 }
3064 return 0;
3065}
3066
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003067static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003068{
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003069 u16 control = 0;
3070
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003071 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003072
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003073 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003074
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003075 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan64988862010-05-10 14:54:14 -03003076 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003077 l2cap_send_sframe(chan, control);
3078 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003079 }
3080
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003081 if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
3082 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003083
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003084 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003085
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003086 if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003087 chan->frames_sent == 0) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003088 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003089 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003090 }
3091}
3092
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003093static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003094{
3095 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003096 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003097
3098 bt_cb(skb)->tx_seq = tx_seq;
3099 bt_cb(skb)->sar = sar;
3100
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003101 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003102 if (!next_skb) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003103 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003104 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003105 }
3106
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003107 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003108 if (tx_seq_offset < 0)
3109 tx_seq_offset += 64;
3110
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003111 do {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003112 if (bt_cb(next_skb)->tx_seq == tx_seq)
3113 return -EINVAL;
3114
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003115 next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003116 chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003117 if (next_tx_seq_offset < 0)
3118 next_tx_seq_offset += 64;
3119
3120 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003121 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003122 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003123 }
3124
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003125 if (skb_queue_is_last(&chan->srej_q, next_skb))
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003126 break;
3127
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003128 } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003129
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003130 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003131
3132 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003133}
3134
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003135static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003136{
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003137 struct sk_buff *_skb;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003138 int err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003139
3140 switch (control & L2CAP_CTRL_SAR) {
3141 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003142 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003143 goto drop;
3144
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003145 return chan->ops->recv(chan->data, skb);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003146
3147 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003148 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003149 goto drop;
3150
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003151 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003152
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003153 if (chan->sdu_len > chan->imtu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003154 goto disconnect;
3155
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003156 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3157 if (!chan->sdu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003158 return -ENOMEM;
3159
3160 /* pull sdu_len bytes only after alloc, because of Local Busy
3161 * condition we have to be sure that this will be executed
3162 * only once, i.e., when alloc does not fail */
3163 skb_pull(skb, 2);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003164
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003165 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003166
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003167 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003168 chan->partial_sdu_len = skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003169 break;
3170
3171 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003172 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003173 goto disconnect;
3174
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003175 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003176 goto disconnect;
3177
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003178 chan->partial_sdu_len += skb->len;
3179 if (chan->partial_sdu_len > chan->sdu_len)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003180 goto drop;
3181
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003182 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003183
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003184 break;
3185
3186 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003187 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003188 goto disconnect;
3189
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003190 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003191 goto disconnect;
3192
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003193 if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003194 chan->partial_sdu_len += skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003195
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003196 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003197 goto drop;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003198
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003199 if (chan->partial_sdu_len != chan->sdu_len)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003200 goto drop;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003201
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003202 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003203 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003204
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003205 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003206 if (!_skb) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003207 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003208 return -ENOMEM;
3209 }
3210
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003211 err = chan->ops->recv(chan->data, _skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003212 if (err < 0) {
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003213 kfree_skb(_skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003214 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003215 return err;
3216 }
3217
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003218 chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
3219 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003220
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003221 kfree_skb(chan->sdu);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003222 break;
3223 }
3224
3225 kfree_skb(skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003226 return 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003227
3228drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003229 kfree_skb(chan->sdu);
3230 chan->sdu = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003231
3232disconnect:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003233 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003234 kfree_skb(skb);
3235 return 0;
3236}
3237
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003238static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003239{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003240 struct sk_buff *skb;
3241 u16 control;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003242 int err;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003243
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003244 while ((skb = skb_dequeue(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003245 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003246 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003247 if (err < 0) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003248 skb_queue_head(&chan->busy_q, skb);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003249 return -EBUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003250 }
3251
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003252 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003253 }
3254
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003255 if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003256 goto done;
3257
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003258 control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003259 control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003260 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003261 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003262
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003263 __clear_retrans_timer(chan);
3264 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003265
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003266 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003267
3268done:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003269 chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
3270 chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003271
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003272 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003273
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003274 return 0;
3275}
3276
3277static void l2cap_busy_work(struct work_struct *work)
3278{
3279 DECLARE_WAITQUEUE(wait, current);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003280 struct l2cap_chan *chan =
3281 container_of(work, struct l2cap_chan, busy_work);
3282 struct sock *sk = chan->sk;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003283 int n_tries = 0, timeo = HZ/5, err;
3284 struct sk_buff *skb;
3285
3286 lock_sock(sk);
3287
3288 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003289 while ((skb = skb_peek(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003290 set_current_state(TASK_INTERRUPTIBLE);
3291
3292 if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
3293 err = -EBUSY;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003294 l2cap_send_disconn_req(chan->conn, chan, EBUSY);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003295 break;
3296 }
3297
3298 if (!timeo)
3299 timeo = HZ/5;
3300
3301 if (signal_pending(current)) {
3302 err = sock_intr_errno(timeo);
3303 break;
3304 }
3305
3306 release_sock(sk);
3307 timeo = schedule_timeout(timeo);
3308 lock_sock(sk);
3309
3310 err = sock_error(sk);
3311 if (err)
3312 break;
3313
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003314 if (l2cap_try_push_rx_skb(chan) == 0)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003315 break;
3316 }
3317
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003318 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02003319 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003320
3321 release_sock(sk);
3322}
3323
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003324static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003325{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003326 int sctrl, err;
3327
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003328 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003329 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003330 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003331 return l2cap_try_push_rx_skb(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003332
3333
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003334 }
3335
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003336 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003337 if (err >= 0) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003338 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003339 return err;
3340 }
3341
3342 /* Busy Condition */
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003343 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003344
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003345 chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003346 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003347 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003348
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003349 sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003350 sctrl |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003351 l2cap_send_sframe(chan, sctrl);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003352
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003353 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003354
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003355 __clear_ack_timer(chan);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003356
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003357 queue_work(_busy_wq, &chan->busy_work);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003358
3359 return err;
3360}
3361
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003362static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003363{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003364 struct sk_buff *_skb;
3365 int err = -EINVAL;
3366
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003367 /*
3368 * TODO: We have to notify the userland if some data is lost with the
3369 * Streaming Mode.
3370 */
3371
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003372 switch (control & L2CAP_CTRL_SAR) {
3373 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003374 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003375 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003376 break;
3377 }
3378
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003379 err = chan->ops->recv(chan->data, skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003380 if (!err)
3381 return 0;
3382
3383 break;
3384
3385 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003386 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003387 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003388 break;
3389 }
3390
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003391 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003392 skb_pull(skb, 2);
3393
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003394 if (chan->sdu_len > chan->imtu) {
Gustavo F. Padovan052897c2010-05-01 16:15:40 -03003395 err = -EMSGSIZE;
3396 break;
3397 }
3398
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003399 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3400 if (!chan->sdu) {
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003401 err = -ENOMEM;
3402 break;
3403 }
3404
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003405 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003406
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003407 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003408 chan->partial_sdu_len = skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003409 err = 0;
3410 break;
3411
3412 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003413 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003414 break;
3415
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003416 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003417
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003418 chan->partial_sdu_len += skb->len;
3419 if (chan->partial_sdu_len > chan->sdu_len)
3420 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003421 else
3422 err = 0;
3423
3424 break;
3425
3426 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003427 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003428 break;
3429
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003430 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003431
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003432 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003433 chan->partial_sdu_len += skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003434
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003435 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003436 goto drop;
3437
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003438 if (chan->partial_sdu_len == chan->sdu_len) {
3439 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003440 err = chan->ops->recv(chan->data, _skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003441 if (err < 0)
3442 kfree_skb(_skb);
3443 }
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003444 err = 0;
3445
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003446drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003447 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003448 break;
3449 }
3450
3451 kfree_skb(skb);
3452 return err;
3453}
3454
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003455static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003456{
3457 struct sk_buff *skb;
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003458 u16 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003459
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003460 while ((skb = skb_peek(&chan->srej_q))) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003461 if (bt_cb(skb)->tx_seq != tx_seq)
3462 break;
3463
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003464 skb = skb_dequeue(&chan->srej_q);
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003465 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003466 l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003467 chan->buffer_seq_srej =
3468 (chan->buffer_seq_srej + 1) % 64;
Gustavo F. Padovan8ff50ec2010-05-10 19:34:11 -03003469 tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003470 }
3471}
3472
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003473static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003474{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003475 struct srej_list *l, *tmp;
3476 u16 control;
3477
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003478 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003479 if (l->tx_seq == tx_seq) {
3480 list_del(&l->list);
3481 kfree(l);
3482 return;
3483 }
3484 control = L2CAP_SUPER_SELECT_REJECT;
3485 control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003486 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003487 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003488 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003489 }
3490}
3491
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003492static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003493{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003494 struct srej_list *new;
3495 u16 control;
3496
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003497 while (tx_seq != chan->expected_tx_seq) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003498 control = L2CAP_SUPER_SELECT_REJECT;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003499 control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003500 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003501
3502 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003503 new->tx_seq = chan->expected_tx_seq;
3504 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003505 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003506 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003507 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003508}
3509
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003510static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003511{
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003512 u8 tx_seq = __get_txseq(rx_control);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003513 u8 req_seq = __get_reqseq(rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003514 u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003515 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003516 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003517 int err = 0;
3518
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003519 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
3520 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003521
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003522 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003523 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003524 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003525 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003526 __set_retrans_timer(chan);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003527 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003528 }
3529
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003530 chan->expected_ack_seq = req_seq;
3531 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003532
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003533 if (tx_seq == chan->expected_tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003534 goto expected;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003535
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003536 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003537 if (tx_seq_offset < 0)
3538 tx_seq_offset += 64;
3539
3540 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003541 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003542 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003543 goto drop;
3544 }
3545
Mat Martineaue6949282011-06-03 16:21:10 -07003546 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003547 goto drop;
3548
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003549 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003550 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003551
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003552 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003553 struct srej_list, list);
3554 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003555 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003556 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003557
3558 list_del(&first->list);
3559 kfree(first);
3560
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003561 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003562 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003563 chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
3564 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003565 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003566 }
3567 } else {
3568 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003569
3570 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003571 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003572 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003573
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003574 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003575 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003576 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003577 return 0;
3578 }
3579 }
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003580 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003581 }
3582 } else {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003583 expected_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003584 (chan->expected_tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003585 if (expected_tx_seq_offset < 0)
3586 expected_tx_seq_offset += 64;
3587
3588 /* duplicated tx_seq */
3589 if (tx_seq_offset < expected_tx_seq_offset)
3590 goto drop;
3591
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003592 chan->conn_state |= L2CAP_CONN_SREJ_SENT;
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003593
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003594 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003595
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003596 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003597 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003598
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003599 __skb_queue_head_init(&chan->srej_q);
3600 __skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003601 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003602
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003603 chan->conn_state |= L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003604
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003605 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003606
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003607 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003608 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003609 return 0;
3610
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003611expected:
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003612 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003613
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003614 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003615 bt_cb(skb)->tx_seq = tx_seq;
3616 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003617 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003618 return 0;
3619 }
3620
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003621 err = l2cap_push_rx_skb(chan, skb, rx_control);
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003622 if (err < 0)
3623 return 0;
3624
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003625 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003626 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3627 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003628 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003629 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003630 }
3631
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003632 __set_ack_timer(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003633
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003634 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3635 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003636 l2cap_send_ack(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003637
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003638 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003639
3640drop:
3641 kfree_skb(skb);
3642 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003643}
3644
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003645static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003646{
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003647 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003648 rx_control);
3649
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003650 chan->expected_ack_seq = __get_reqseq(rx_control);
3651 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003652
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003653 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003654 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3655 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
3656 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003657 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003658 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003659
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003660 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3661 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003662 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003663 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003664 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003665
3666 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003667 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003668
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003669 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3670 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003671 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003672 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003673
3674 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003675 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003676 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003677 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003678
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003679 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3680 if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
3681 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003682 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003683 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003684 }
3685}
3686
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003687static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003688{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003689 u8 tx_seq = __get_reqseq(rx_control);
3690
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003691 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003692
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003693 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003694
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003695 chan->expected_ack_seq = tx_seq;
3696 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003697
3698 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003699 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3700 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003701 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003702 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003703 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003704 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003705
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003706 if (chan->conn_state & L2CAP_CONN_WAIT_F)
3707 chan->conn_state |= L2CAP_CONN_REJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003708 }
3709}
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003710static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003711{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003712 u8 tx_seq = __get_reqseq(rx_control);
3713
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003714 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003715
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003716 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003717
3718 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003719 chan->expected_ack_seq = tx_seq;
3720 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003721
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003722 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3723 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003724
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003725 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003726
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003727 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003728 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003729 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003730 }
3731 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003732 if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003733 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003734 chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003735 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003736 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003737 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003738 l2cap_retransmit_one_frame(chan, tx_seq);
3739 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003740 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003741 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003742 }
3743 }
3744}
3745
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003746static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003747{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003748 u8 tx_seq = __get_reqseq(rx_control);
3749
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003750 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003751
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003752 chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003753 chan->expected_ack_seq = tx_seq;
3754 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003755
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003756 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003757 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003758
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003759 if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003760 __clear_retrans_timer(chan);
Gustavo F. Padovana2e12a22010-05-05 19:58:27 -03003761 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003762 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003763 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003764 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003765
3766 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003767 l2cap_send_srejtail(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003768 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003769 l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003770}
3771
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003772static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003773{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003774 BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003775
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003776 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003777 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003778 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003779 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003780 __set_retrans_timer(chan);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003781 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003782 }
3783
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003784 switch (rx_control & L2CAP_CTRL_SUPERVISE) {
3785 case L2CAP_SUPER_RCV_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003786 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003787 break;
3788
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003789 case L2CAP_SUPER_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003790 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003791 break;
3792
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003793 case L2CAP_SUPER_SELECT_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003794 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003795 break;
3796
3797 case L2CAP_SUPER_RCV_NOT_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003798 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003799 break;
3800 }
3801
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03003802 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003803 return 0;
3804}
3805
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003806static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
3807{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003808 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003809 u16 control;
3810 u8 req_seq;
3811 int len, next_tx_seq_offset, req_seq_offset;
3812
3813 control = get_unaligned_le16(skb->data);
3814 skb_pull(skb, 2);
3815 len = skb->len;
3816
3817 /*
3818 * We can just drop the corrupted I-frame here.
3819 * Receiver will miss it and start proper recovery
3820 * procedures and ask retransmission.
3821 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003822 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003823 goto drop;
3824
3825 if (__is_sar_start(control) && __is_iframe(control))
3826 len -= 2;
3827
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003828 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003829 len -= 2;
3830
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003831 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003832 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003833 goto drop;
3834 }
3835
3836 req_seq = __get_reqseq(control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003837 req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003838 if (req_seq_offset < 0)
3839 req_seq_offset += 64;
3840
3841 next_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003842 (chan->next_tx_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003843 if (next_tx_seq_offset < 0)
3844 next_tx_seq_offset += 64;
3845
3846 /* check for invalid req-seq */
3847 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003848 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003849 goto drop;
3850 }
3851
3852 if (__is_iframe(control)) {
3853 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003854 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003855 goto drop;
3856 }
3857
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003858 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003859 } else {
3860 if (len != 0) {
3861 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003862 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003863 goto drop;
3864 }
3865
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003866 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003867 }
3868
3869 return 0;
3870
3871drop:
3872 kfree_skb(skb);
3873 return 0;
3874}
3875
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
3877{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003878 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07003879 struct sock *sk = NULL;
Nathan Holstein51893f82010-06-09 15:46:25 -04003880 u16 control;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003881 u8 tx_seq;
3882 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003883
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003884 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003885 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 BT_DBG("unknown cid 0x%4.4x", cid);
3887 goto drop;
3888 }
3889
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003890 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003891
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003892 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003894 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895 goto drop;
3896
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003897 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003898 case L2CAP_MODE_BASIC:
3899 /* If socket recv buffers overflows we drop data here
3900 * which is *bad* because L2CAP has to be reliable.
3901 * But we don't have any other choice. L2CAP doesn't
3902 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003904 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003905 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003907 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003908 goto done;
3909 break;
3910
3911 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003912 if (!sock_owned_by_user(sk)) {
3913 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003914 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003915 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003916 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003917 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003918
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02003919 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003920
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003921 case L2CAP_MODE_STREAMING:
3922 control = get_unaligned_le16(skb->data);
3923 skb_pull(skb, 2);
3924 len = skb->len;
3925
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003926 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03003927 goto drop;
3928
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003929 if (__is_sar_start(control))
3930 len -= 2;
3931
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003932 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003933 len -= 2;
3934
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003935 if (len > chan->mps || len < 0 || __is_sframe(control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003936 goto drop;
3937
3938 tx_seq = __get_txseq(control);
3939
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003940 if (chan->expected_tx_seq == tx_seq)
3941 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003942 else
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003943 chan->expected_tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003944
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003945 l2cap_streaming_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003946
3947 goto done;
3948
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003949 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003950 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003951 break;
3952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953
3954drop:
3955 kfree_skb(skb);
3956
3957done:
Marcel Holtmann01394182006-07-03 10:02:46 +02003958 if (sk)
3959 bh_unlock_sock(sk);
3960
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 return 0;
3962}
3963
Al Viro8e036fc2007-07-29 00:16:36 -07003964static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003966 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003967 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003969 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
3970 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 goto drop;
3972
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003973 sk = chan->sk;
3974
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00003975 bh_lock_sock(sk);
3976
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 BT_DBG("sk %p, len %d", sk, skb->len);
3978
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003979 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003980 goto drop;
3981
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003982 if (l2cap_pi(sk)->chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 goto drop;
3984
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003985 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 goto done;
3987
3988drop:
3989 kfree_skb(skb);
3990
3991done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03003992 if (sk)
3993 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 return 0;
3995}
3996
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003997static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
3998{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003999 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004000 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004001
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004002 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4003 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004004 goto drop;
4005
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004006 sk = chan->sk;
4007
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004008 bh_lock_sock(sk);
4009
4010 BT_DBG("sk %p, len %d", sk, skb->len);
4011
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004012 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004013 goto drop;
4014
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004015 if (l2cap_pi(sk)->chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004016 goto drop;
4017
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004018 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004019 goto done;
4020
4021drop:
4022 kfree_skb(skb);
4023
4024done:
4025 if (sk)
4026 bh_unlock_sock(sk);
4027 return 0;
4028}
4029
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4031{
4032 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004033 u16 cid, len;
4034 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035
4036 skb_pull(skb, L2CAP_HDR_SIZE);
4037 cid = __le16_to_cpu(lh->cid);
4038 len = __le16_to_cpu(lh->len);
4039
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004040 if (len != skb->len) {
4041 kfree_skb(skb);
4042 return;
4043 }
4044
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4046
4047 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004048 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004049 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 l2cap_sig_channel(conn, skb);
4051 break;
4052
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004053 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004054 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 skb_pull(skb, 2);
4056 l2cap_conless_channel(conn, psm, skb);
4057 break;
4058
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004059 case L2CAP_CID_LE_DATA:
4060 l2cap_att_channel(conn, cid, skb);
4061 break;
4062
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 default:
4064 l2cap_data_channel(conn, cid, skb);
4065 break;
4066 }
4067}
4068
4069/* ---- L2CAP interface with lower layer (HCI) ---- */
4070
4071static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4072{
4073 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004074 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075
4076 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004077 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078
4079 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4080
4081 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004082 read_lock(&chan_list_lock);
4083 list_for_each_entry(c, &chan_list, global_l) {
4084 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004085
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004086 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 continue;
4088
4089 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004090 lm1 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004091 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004092 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004093 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004094 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4095 lm2 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004096 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004097 lm2 |= HCI_LM_MASTER;
4098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004100 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101
4102 return exact ? lm1 : lm2;
4103}
4104
4105static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4106{
Marcel Holtmann01394182006-07-03 10:02:46 +02004107 struct l2cap_conn *conn;
4108
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4110
Ville Tervoacd7d372011-02-10 22:38:49 -03004111 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004112 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113
4114 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115 conn = l2cap_conn_add(hcon, status);
4116 if (conn)
4117 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004118 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004119 l2cap_conn_del(hcon, bt_err(status));
4120
4121 return 0;
4122}
4123
Marcel Holtmann2950f212009-02-12 14:02:50 +01004124static int l2cap_disconn_ind(struct hci_conn *hcon)
4125{
4126 struct l2cap_conn *conn = hcon->l2cap_data;
4127
4128 BT_DBG("hcon %p", hcon);
4129
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004130 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004131 return 0x13;
4132
4133 return conn->disc_reason;
4134}
4135
4136static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137{
4138 BT_DBG("hcon %p reason %d", hcon, reason);
4139
Ville Tervoacd7d372011-02-10 22:38:49 -03004140 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004141 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142
4143 l2cap_conn_del(hcon, bt_err(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004144
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145 return 0;
4146}
4147
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004148static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004149{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004150 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004151 return;
4152
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004153 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004154 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004155 __clear_chan_timer(chan);
4156 __set_chan_timer(chan, HZ * 5);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004157 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004158 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004159 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004160 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004161 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004162 }
4163}
4164
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004165static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004167 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004168 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169
Marcel Holtmann01394182006-07-03 10:02:46 +02004170 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004172
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 BT_DBG("conn %p", conn);
4174
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004175 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004177 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004178 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004179
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 bh_lock_sock(sk);
4181
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004182 if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004183 bh_unlock_sock(sk);
4184 continue;
4185 }
4186
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004187 if (!status && (chan->state == BT_CONNECTED ||
4188 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004189 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004190 bh_unlock_sock(sk);
4191 continue;
4192 }
4193
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004194 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004195 if (!status) {
4196 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004197 req.scid = cpu_to_le16(chan->scid);
4198 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004199
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004200 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004201 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004202
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004203 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004204 L2CAP_CONN_REQ, sizeof(req), &req);
4205 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004206 __clear_chan_timer(chan);
4207 __set_chan_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004208 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004209 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004210 struct l2cap_conn_rsp rsp;
4211 __u16 result;
4212
4213 if (!status) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004214 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004215 result = L2CAP_CR_SUCCESS;
4216 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004217 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004218 __set_chan_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004219 result = L2CAP_CR_SEC_BLOCK;
4220 }
4221
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004222 rsp.scid = cpu_to_le16(chan->dcid);
4223 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004224 rsp.result = cpu_to_le16(result);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02004225 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004226 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4227 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228 }
4229
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 bh_unlock_sock(sk);
4231 }
4232
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004233 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004234
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235 return 0;
4236}
4237
4238static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4239{
4240 struct l2cap_conn *conn = hcon->l2cap_data;
4241
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004242 if (!conn)
4243 conn = l2cap_conn_add(hcon, 0);
4244
4245 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 goto drop;
4247
4248 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4249
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004250 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004252 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004253 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 int len;
4255
4256 if (conn->rx_len) {
4257 BT_ERR("Unexpected start frame (len %d)", skb->len);
4258 kfree_skb(conn->rx_skb);
4259 conn->rx_skb = NULL;
4260 conn->rx_len = 0;
4261 l2cap_conn_unreliable(conn, ECOMM);
4262 }
4263
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004264 /* Start fragment always begin with Basic L2CAP header */
4265 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 BT_ERR("Frame is too short (len %d)", skb->len);
4267 l2cap_conn_unreliable(conn, ECOMM);
4268 goto drop;
4269 }
4270
4271 hdr = (struct l2cap_hdr *) skb->data;
4272 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004273 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274
4275 if (len == skb->len) {
4276 /* Complete frame received */
4277 l2cap_recv_frame(conn, skb);
4278 return 0;
4279 }
4280
4281 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4282
4283 if (skb->len > len) {
4284 BT_ERR("Frame is too long (len %d, expected len %d)",
4285 skb->len, len);
4286 l2cap_conn_unreliable(conn, ECOMM);
4287 goto drop;
4288 }
4289
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004290 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004291
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004292 if (chan && chan->sk) {
4293 struct sock *sk = chan->sk;
4294
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004295 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004296 BT_ERR("Frame exceeding recv MTU (len %d, "
4297 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004298 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004299 bh_unlock_sock(sk);
4300 l2cap_conn_unreliable(conn, ECOMM);
4301 goto drop;
4302 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004303 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004304 }
4305
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004307 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4308 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 goto drop;
4310
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004311 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004312 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 conn->rx_len = len - skb->len;
4314 } else {
4315 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4316
4317 if (!conn->rx_len) {
4318 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4319 l2cap_conn_unreliable(conn, ECOMM);
4320 goto drop;
4321 }
4322
4323 if (skb->len > conn->rx_len) {
4324 BT_ERR("Fragment is too long (len %d, expected %d)",
4325 skb->len, conn->rx_len);
4326 kfree_skb(conn->rx_skb);
4327 conn->rx_skb = NULL;
4328 conn->rx_len = 0;
4329 l2cap_conn_unreliable(conn, ECOMM);
4330 goto drop;
4331 }
4332
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004333 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004334 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 conn->rx_len -= skb->len;
4336
4337 if (!conn->rx_len) {
4338 /* Complete frame received */
4339 l2cap_recv_frame(conn, conn->rx_skb);
4340 conn->rx_skb = NULL;
4341 }
4342 }
4343
4344drop:
4345 kfree_skb(skb);
4346 return 0;
4347}
4348
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004349static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004351 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004353 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004355 list_for_each_entry(c, &chan_list, global_l) {
4356 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004358 seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004359 batostr(&bt_sk(sk)->src),
4360 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004361 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004362 c->scid, c->dcid, c->imtu, c->omtu,
4363 c->sec_level, c->mode);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004366 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004367
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004368 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369}
4370
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004371static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4372{
4373 return single_open(file, l2cap_debugfs_show, inode->i_private);
4374}
4375
4376static const struct file_operations l2cap_debugfs_fops = {
4377 .open = l2cap_debugfs_open,
4378 .read = seq_read,
4379 .llseek = seq_lseek,
4380 .release = single_release,
4381};
4382
4383static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385static struct hci_proto l2cap_hci_proto = {
4386 .name = "L2CAP",
4387 .id = HCI_PROTO_L2CAP,
4388 .connect_ind = l2cap_connect_ind,
4389 .connect_cfm = l2cap_connect_cfm,
4390 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004391 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004392 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 .recv_acldata = l2cap_recv_acldata
4394};
4395
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004396int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397{
4398 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004399
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004400 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 if (err < 0)
4402 return err;
4403
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004404 _busy_wq = create_singlethread_workqueue("l2cap");
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004405 if (!_busy_wq) {
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004406 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 goto error;
4408 }
4409
4410 err = hci_register_proto(&l2cap_hci_proto);
4411 if (err < 0) {
4412 BT_ERR("L2CAP protocol registration failed");
4413 bt_sock_unregister(BTPROTO_L2CAP);
4414 goto error;
4415 }
4416
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004417 if (bt_debugfs) {
4418 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4419 bt_debugfs, NULL, &l2cap_debugfs_fops);
4420 if (!l2cap_debugfs)
4421 BT_ERR("Failed to create L2CAP debug file");
4422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 return 0;
4425
4426error:
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004427 destroy_workqueue(_busy_wq);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004428 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 return err;
4430}
4431
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004432void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004434 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004436 flush_workqueue(_busy_wq);
4437 destroy_workqueue(_busy_wq);
4438
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4440 BT_ERR("L2CAP protocol unregistration failed");
4441
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004442 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443}
4444
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004445module_param(disable_ertm, bool, 0644);
4446MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");