blob: 3e450f4a3125338c8d38b68d1441d545ec9ad2e3 [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.
Gustavo F. Padovan590051d2011-12-18 13:39:33 -02006 Copyright (C) 2011 ProFUSION Embedded Systems
Linus Torvalds1da177e2005-04-16 15:20:36 -07007
8 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation;
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
17 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090023 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 SOFTWARE IS DISCLAIMED.
26*/
27
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020028/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31
32#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080033#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/errno.h>
35#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/sched.h>
37#include <linux/slab.h>
38#include <linux/poll.h>
39#include <linux/fcntl.h>
40#include <linux/init.h>
41#include <linux/interrupt.h>
42#include <linux/socket.h>
43#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080045#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010046#include <linux/debugfs.h>
47#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030048#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030049#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <net/sock.h>
51
52#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <asm/unaligned.h>
54
55#include <net/bluetooth/bluetooth.h>
56#include <net/bluetooth/hci_core.h>
57#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030058#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Rusty Russelleb939922011-12-19 14:08:01 +000060bool disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020061
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070062static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070063static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
69 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030070static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
71 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030072static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030073static void l2cap_send_disconn_req(struct l2cap_conn *conn,
74 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Marcel Holtmann01394182006-07-03 10:02:46 +020076/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030077
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030078static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020079{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020080 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030081
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020082 list_for_each_entry(c, &conn->chan_l, list) {
83 if (c->dcid == cid)
84 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020085 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020086 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020087}
88
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030089static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020090{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020091 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030092
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020093 list_for_each_entry(c, &conn->chan_l, list) {
94 if (c->scid == cid)
95 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020096 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020097 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020098}
99
100/* Find channel with given SCID.
101 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300102static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200103{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300104 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300105
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200106 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300107 c = __l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200108 mutex_unlock(&conn->chan_lock);
109
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300110 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200111}
112
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300113static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200114{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200115 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300116
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200117 list_for_each_entry(c, &conn->chan_l, list) {
118 if (c->ident == ident)
119 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200120 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200121 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200122}
123
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300124static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200125{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300126 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300127
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200128 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300129 c = __l2cap_get_chan_by_ident(conn, ident);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200130 mutex_unlock(&conn->chan_lock);
131
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300132 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200133}
134
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300135static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300136{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300137 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300138
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300139 list_for_each_entry(c, &chan_list, global_l) {
140 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100141 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300142 }
Szymon Janc250938c2011-11-16 09:32:22 +0100143 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300144}
145
146int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
147{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300148 int err;
149
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200150 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300151
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300152 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300153 err = -EADDRINUSE;
154 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300155 }
156
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300157 if (psm) {
158 chan->psm = psm;
159 chan->sport = psm;
160 err = 0;
161 } else {
162 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300163
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300164 err = -EINVAL;
165 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300166 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300167 chan->psm = cpu_to_le16(p);
168 chan->sport = cpu_to_le16(p);
169 err = 0;
170 break;
171 }
172 }
173
174done:
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200175 write_unlock(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300176 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300177}
178
179int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
180{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200181 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300182
183 chan->scid = scid;
184
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200185 write_unlock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300186
187 return 0;
188}
189
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300190static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200191{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300192 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200193
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300194 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300195 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200196 return cid;
197 }
198
199 return 0;
200}
201
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200202static void __l2cap_state_change(struct l2cap_chan *chan, int state)
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300203{
Andrei Emeltchenko42d2d872012-02-17 11:40:57 +0200204 BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200205 state_to_string(state));
206
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300207 chan->state = state;
208 chan->ops->state_change(chan->data, state);
209}
210
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200211static void l2cap_state_change(struct l2cap_chan *chan, int state)
212{
213 struct sock *sk = chan->sk;
214
215 lock_sock(sk);
216 __l2cap_state_change(chan, state);
217 release_sock(sk);
218}
219
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200220static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
221{
222 struct sock *sk = chan->sk;
223
224 sk->sk_err = err;
225}
226
227static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
228{
229 struct sock *sk = chan->sk;
230
231 lock_sock(sk);
232 __l2cap_chan_set_err(chan, err);
233 release_sock(sk);
234}
235
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300236static void l2cap_chan_timeout(struct work_struct *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300237{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300238 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
239 chan_timer.work);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200240 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300241 int reason;
242
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200243 BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300244
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200245 mutex_lock(&conn->chan_lock);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200246 l2cap_chan_lock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300247
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300248 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300249 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300250 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300251 chan->sec_level != BT_SECURITY_SDP)
252 reason = ECONNREFUSED;
253 else
254 reason = ETIMEDOUT;
255
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300256 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300257
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200258 l2cap_chan_unlock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300259
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300260 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200261 mutex_unlock(&conn->chan_lock);
262
Ulisses Furquim371fd832011-12-21 20:02:36 -0200263 l2cap_chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300264}
265
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300266struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200267{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300268 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200269
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300270 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
271 if (!chan)
272 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200273
Andrei Emeltchenkoc03b3552012-02-21 12:54:56 +0200274 mutex_init(&chan->lock);
275
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300276 chan->sk = sk;
277
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200278 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300279 list_add(&chan->global_l, &chan_list);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200280 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300281
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300282 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300283
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300284 chan->state = BT_OPEN;
285
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300286 atomic_set(&chan->refcnt, 1);
287
Szymon Jancabc545b2011-11-03 16:05:44 +0100288 BT_DBG("sk %p chan %p", sk, chan);
289
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300290 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200291}
292
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300293void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300294{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200295 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300296 list_del(&chan->global_l);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200297 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300298
Ulisses Furquim371fd832011-12-21 20:02:36 -0200299 l2cap_chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300300}
301
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200302void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200303{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300304 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300305 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200306
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200307 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100308
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300309 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200310
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200311 switch (chan->chan_type) {
312 case L2CAP_CHAN_CONN_ORIENTED:
Ville Tervob62f3282011-02-10 22:38:50 -0300313 if (conn->hcon->type == LE_LINK) {
314 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300315 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300316 chan->scid = L2CAP_CID_LE_DATA;
317 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300318 } else {
319 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300320 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300321 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300322 }
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200323 break;
324
325 case L2CAP_CHAN_CONN_LESS:
Marcel Holtmann01394182006-07-03 10:02:46 +0200326 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300327 chan->scid = L2CAP_CID_CONN_LESS;
328 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300329 chan->omtu = L2CAP_DEFAULT_MTU;
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200330 break;
331
332 default:
Marcel Holtmann01394182006-07-03 10:02:46 +0200333 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300334 chan->scid = L2CAP_CID_SIGNALING;
335 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300336 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200337 }
338
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300339 chan->local_id = L2CAP_BESTEFFORT_ID;
340 chan->local_stype = L2CAP_SERV_BESTEFFORT;
341 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
342 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
343 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
344 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
345
Ulisses Furquim371fd832011-12-21 20:02:36 -0200346 l2cap_chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300347
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200348 list_add(&chan->list, &conn->chan_l);
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200349}
350
351void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
352{
353 mutex_lock(&conn->chan_lock);
354 __l2cap_chan_add(conn, chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200355 mutex_unlock(&conn->chan_lock);
Marcel Holtmann01394182006-07-03 10:02:46 +0200356}
357
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300358static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200359{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300360 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300361 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200362 struct sock *parent = bt_sk(sk)->parent;
363
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300364 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200365
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300366 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200367
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900368 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300369 /* Delete from channel list */
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200370 list_del(&chan->list);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200371
Ulisses Furquim371fd832011-12-21 20:02:36 -0200372 l2cap_chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300373
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300374 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200375 hci_conn_put(conn->hcon);
376 }
377
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200378 lock_sock(sk);
379
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200380 __l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200381 sock_set_flag(sk, SOCK_ZAPPED);
382
383 if (err)
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200384 __l2cap_chan_set_err(chan, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200385
386 if (parent) {
387 bt_accept_unlink(sk);
388 parent->sk_data_ready(parent, 0);
389 } else
390 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300391
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200392 release_sock(sk);
393
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300394 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
395 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300396 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300397
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300398 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300399
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300400 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300401 struct srej_list *l, *tmp;
402
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300403 __clear_retrans_timer(chan);
404 __clear_monitor_timer(chan);
405 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300406
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300407 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300408
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300409 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300410 list_del(&l->list);
411 kfree(l);
412 }
413 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200414}
415
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300416static void l2cap_chan_cleanup_listen(struct sock *parent)
417{
418 struct sock *sk;
419
420 BT_DBG("parent %p", parent);
421
422 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300423 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300424 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200425
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200426 l2cap_chan_lock(chan);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300427 __clear_chan_timer(chan);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300428 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200429 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200430
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300431 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300432 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300433}
434
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300435void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300436{
437 struct l2cap_conn *conn = chan->conn;
438 struct sock *sk = chan->sk;
439
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200440 BT_DBG("chan %p state %s sk %p", chan,
441 state_to_string(chan->state), sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300442
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300443 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300444 case BT_LISTEN:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200445 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300446 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300447
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200448 __l2cap_state_change(chan, BT_CLOSED);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300449 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200450 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300451 break;
452
453 case BT_CONNECTED:
454 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300455 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300456 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300457 __clear_chan_timer(chan);
458 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300459 l2cap_send_disconn_req(conn, chan, reason);
460 } else
461 l2cap_chan_del(chan, reason);
462 break;
463
464 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300465 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300466 conn->hcon->type == ACL_LINK) {
467 struct l2cap_conn_rsp rsp;
468 __u16 result;
469
470 if (bt_sk(sk)->defer_setup)
471 result = L2CAP_CR_SEC_BLOCK;
472 else
473 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300474 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300475
476 rsp.scid = cpu_to_le16(chan->dcid);
477 rsp.dcid = cpu_to_le16(chan->scid);
478 rsp.result = cpu_to_le16(result);
479 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
480 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
481 sizeof(rsp), &rsp);
482 }
483
484 l2cap_chan_del(chan, reason);
485 break;
486
487 case BT_CONNECT:
488 case BT_DISCONN:
489 l2cap_chan_del(chan, reason);
490 break;
491
492 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200493 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300494 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200495 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300496 break;
497 }
498}
499
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300500static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530501{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300502 if (chan->chan_type == L2CAP_CHAN_RAW) {
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_DEDICATED_BONDING_MITM;
506 case BT_SECURITY_MEDIUM:
507 return HCI_AT_DEDICATED_BONDING;
508 default:
509 return HCI_AT_NO_BONDING;
510 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300511 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300512 if (chan->sec_level == BT_SECURITY_LOW)
513 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530514
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300515 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530516 return HCI_AT_NO_BONDING_MITM;
517 else
518 return HCI_AT_NO_BONDING;
519 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300520 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530521 case BT_SECURITY_HIGH:
522 return HCI_AT_GENERAL_BONDING_MITM;
523 case BT_SECURITY_MEDIUM:
524 return HCI_AT_GENERAL_BONDING;
525 default:
526 return HCI_AT_NO_BONDING;
527 }
528 }
529}
530
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200531/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200532int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200533{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300534 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100535 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200536
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300537 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100538
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300539 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200540}
541
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200542static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200543{
544 u8 id;
545
546 /* Get next available identificator.
547 * 1 - 128 are used by kernel.
548 * 129 - 199 are reserved.
549 * 200 - 254 are used by utilities like l2ping, etc.
550 */
551
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200552 spin_lock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200553
554 if (++conn->tx_ident > 128)
555 conn->tx_ident = 1;
556
557 id = conn->tx_ident;
558
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200559 spin_unlock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200560
561 return id;
562}
563
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300564static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200565{
566 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200567 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200568
569 BT_DBG("code 0x%2.2x", code);
570
571 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300572 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200573
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200574 if (lmp_no_flush_capable(conn->hcon->hdev))
575 flags = ACL_START_NO_FLUSH;
576 else
577 flags = ACL_START;
578
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700579 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200580 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700581
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200582 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200583}
584
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200585static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
586{
587 struct hci_conn *hcon = chan->conn->hcon;
588 u16 flags;
589
590 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
591 skb->priority);
592
593 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
594 lmp_no_flush_capable(hcon->hdev))
595 flags = ACL_START_NO_FLUSH;
596 else
597 flags = ACL_START;
598
599 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
600 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300603static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300604{
605 struct sk_buff *skb;
606 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300607 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300608 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300609
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300610 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300611 return;
612
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300613 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
614 hlen = L2CAP_EXT_HDR_SIZE;
615 else
616 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300617
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300618 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300619 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300620
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300621 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300622
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300623 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300624
625 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300626
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300627 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300628 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300629
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300630 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300631 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300632
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300633 skb = bt_skb_alloc(count, GFP_ATOMIC);
634 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300635 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300636
637 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300638 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300639 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300640
641 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300642
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300643 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300644 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
645 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300646 }
647
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200648 skb->priority = HCI_PRIO_MAX;
649 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300650}
651
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300652static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300653{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300654 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300655 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300656 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300657 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300658 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300659
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300660 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300661
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300662 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300663}
664
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300665static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300666{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300667 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300668}
669
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200670static void l2cap_send_conn_req(struct l2cap_chan *chan)
671{
672 struct l2cap_conn *conn = chan->conn;
673 struct l2cap_conn_req req;
674
675 req.scid = cpu_to_le16(chan->scid);
676 req.psm = chan->psm;
677
678 chan->ident = l2cap_get_ident(conn);
679
680 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
681
682 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
683}
684
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300685static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200686{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300687 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200688
689 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100690 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
691 return;
692
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200693 if (l2cap_chan_check_security(chan) &&
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200694 __l2cap_no_conn_pending(chan))
695 l2cap_send_conn_req(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200696 } else {
697 struct l2cap_info_req req;
698 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
699
700 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
701 conn->info_ident = l2cap_get_ident(conn);
702
Marcel Holtmannba13ccd2012-03-01 14:25:33 -0800703 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200704
705 l2cap_send_cmd(conn, conn->info_ident,
706 L2CAP_INFO_REQ, sizeof(req), &req);
707 }
708}
709
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300710static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
711{
712 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300713 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300714 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
715
716 switch (mode) {
717 case L2CAP_MODE_ERTM:
718 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
719 case L2CAP_MODE_STREAMING:
720 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
721 default:
722 return 0x00;
723 }
724}
725
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300726static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300727{
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200728 struct sock *sk = chan->sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300729 struct l2cap_disconn_req req;
730
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300731 if (!conn)
732 return;
733
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300734 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300735 __clear_retrans_timer(chan);
736 __clear_monitor_timer(chan);
737 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300738 }
739
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300740 req.dcid = cpu_to_le16(chan->dcid);
741 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300742 l2cap_send_cmd(conn, l2cap_get_ident(conn),
743 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300744
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200745 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200746 __l2cap_state_change(chan, BT_DISCONN);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200747 __l2cap_chan_set_err(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200748 release_sock(sk);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300749}
750
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200752static void l2cap_conn_start(struct l2cap_conn *conn)
753{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200754 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200755
756 BT_DBG("conn %p", conn);
757
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200758 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200759
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200760 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300761 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300762
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200763 l2cap_chan_lock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200764
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300765 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200766 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200767 continue;
768 }
769
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300770 if (chan->state == BT_CONNECT) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200771 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300772 !__l2cap_no_conn_pending(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200773 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300774 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200775 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300776
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300777 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
778 && test_bit(CONF_STATE2_DEVICE,
779 &chan->conf_state)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300780 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200781 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300782 continue;
783 }
784
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200785 l2cap_send_conn_req(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300786
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300787 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200788 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300789 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300790 rsp.scid = cpu_to_le16(chan->dcid);
791 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200792
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200793 if (l2cap_chan_check_security(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200794 lock_sock(sk);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100795 if (bt_sk(sk)->defer_setup) {
796 struct sock *parent = bt_sk(sk)->parent;
797 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
798 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000799 if (parent)
800 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100801
802 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200803 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100804 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
805 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
806 }
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200807 release_sock(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200808 } else {
809 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
810 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
811 }
812
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300813 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
814 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300815
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300816 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300817 rsp.result != L2CAP_CR_SUCCESS) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200818 l2cap_chan_unlock(chan);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300819 continue;
820 }
821
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300822 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300823 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300824 l2cap_build_conf_req(chan, buf), buf);
825 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200826 }
827
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200828 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200829 }
830
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200831 mutex_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200832}
833
Ville Tervob62f3282011-02-10 22:38:50 -0300834/* Find socket with cid and source bdaddr.
835 * Returns closest match, locked.
836 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300837static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300838{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300839 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300840
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300841 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300842
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300843 list_for_each_entry(c, &chan_list, global_l) {
844 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300845
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300846 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300847 continue;
848
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300849 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300850 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300851 if (!bacmp(&bt_sk(sk)->src, src)) {
852 read_unlock(&chan_list_lock);
853 return c;
854 }
Ville Tervob62f3282011-02-10 22:38:50 -0300855
856 /* Closest match */
857 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300858 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300859 }
860 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300861
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300862 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300863
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300864 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300865}
866
867static void l2cap_le_conn_ready(struct l2cap_conn *conn)
868{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300869 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300870 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300871
872 BT_DBG("");
873
874 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300875 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300876 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300877 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300878 return;
879
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300880 parent = pchan->sk;
881
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300882 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300883
Ville Tervob62f3282011-02-10 22:38:50 -0300884 /* Check for backlog size */
885 if (sk_acceptq_is_full(parent)) {
886 BT_DBG("backlog full %d", parent->sk_ack_backlog);
887 goto clean;
888 }
889
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300890 chan = pchan->ops->new_connection(pchan->data);
891 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300892 goto clean;
893
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300894 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300895
Ville Tervob62f3282011-02-10 22:38:50 -0300896 hci_conn_hold(conn->hcon);
897
Ville Tervob62f3282011-02-10 22:38:50 -0300898 bacpy(&bt_sk(sk)->src, conn->src);
899 bacpy(&bt_sk(sk)->dst, conn->dst);
900
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300901 bt_accept_enqueue(parent, sk);
902
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200903 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300904
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300905 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300906
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200907 __l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300908 parent->sk_data_ready(parent, 0);
909
Ville Tervob62f3282011-02-10 22:38:50 -0300910clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300911 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300912}
913
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200914static void l2cap_chan_ready(struct l2cap_chan *chan)
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300915{
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200916 struct sock *sk = chan->sk;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200917 struct sock *parent;
918
919 lock_sock(sk);
920
921 parent = bt_sk(sk)->parent;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300922
923 BT_DBG("sk %p, parent %p", sk, parent);
924
925 chan->conf_state = 0;
926 __clear_chan_timer(chan);
927
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200928 __l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300929 sk->sk_state_change(sk);
930
931 if (parent)
932 parent->sk_data_ready(parent, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200933
934 release_sock(sk);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300935}
936
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200937static void l2cap_conn_ready(struct l2cap_conn *conn)
938{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300939 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200940
941 BT_DBG("conn %p", conn);
942
Ville Tervob62f3282011-02-10 22:38:50 -0300943 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
944 l2cap_le_conn_ready(conn);
945
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300946 if (conn->hcon->out && conn->hcon->type == LE_LINK)
947 smp_conn_security(conn, conn->hcon->pending_sec_level);
948
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200949 mutex_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200950
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200951 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300952
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200953 l2cap_chan_lock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200954
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300955 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300956 if (smp_conn_security(conn, chan->sec_level))
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200957 l2cap_chan_ready(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300958
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300959 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200960 struct sock *sk = chan->sk;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300961 __clear_chan_timer(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200962 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200963 __l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200964 sk->sk_state_change(sk);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200965 release_sock(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300966
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300967 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300968 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200969
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200970 l2cap_chan_unlock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200971 }
972
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200973 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200974}
975
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200976/* Notify sockets that we cannot guaranty reliability anymore */
977static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
978{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300979 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200980
981 BT_DBG("conn %p", conn);
982
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200983 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200984
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200985 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300986 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200987 __l2cap_chan_set_err(chan, err);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200988 }
989
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200990 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200991}
992
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200993static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200994{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200995 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200996 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200997
Marcel Holtmann984947d2009-02-06 23:35:19 +0100998 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100999 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01001000
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001001 l2cap_conn_start(conn);
1002}
1003
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001004static void l2cap_conn_del(struct hci_conn *hcon, int err)
1005{
1006 struct l2cap_conn *conn = hcon->l2cap_data;
1007 struct l2cap_chan *chan, *l;
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001008
1009 if (!conn)
1010 return;
1011
1012 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1013
1014 kfree_skb(conn->rx_skb);
1015
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001016 mutex_lock(&conn->chan_lock);
1017
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001018 /* Kill channels */
1019 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001020 l2cap_chan_lock(chan);
1021
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001022 l2cap_chan_del(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001023
1024 l2cap_chan_unlock(chan);
1025
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001026 chan->ops->close(chan->data);
1027 }
1028
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001029 mutex_unlock(&conn->chan_lock);
1030
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001031 hci_chan_del(conn->hchan);
1032
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001033 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim127074b2012-01-30 18:26:29 -02001034 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001035
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001036 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim127074b2012-01-30 18:26:29 -02001037 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001038 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001039 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001040
1041 hcon->l2cap_data = NULL;
1042 kfree(conn);
1043}
1044
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001045static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001046{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001047 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1048 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001049
1050 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1051}
1052
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1054{
Marcel Holtmann01394182006-07-03 10:02:46 +02001055 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001056 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Marcel Holtmann01394182006-07-03 10:02:46 +02001058 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 return conn;
1060
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001061 hchan = hci_chan_create(hcon);
1062 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001065 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1066 if (!conn) {
1067 hci_chan_del(hchan);
1068 return NULL;
1069 }
1070
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 hcon->l2cap_data = conn;
1072 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001073 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001075 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001076
Ville Tervoacd7d372011-02-10 22:38:49 -03001077 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1078 conn->mtu = hcon->hdev->le_mtu;
1079 else
1080 conn->mtu = hcon->hdev->acl_mtu;
1081
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 conn->src = &hcon->hdev->bdaddr;
1083 conn->dst = &hcon->dst;
1084
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001085 conn->feat_mask = 0;
1086
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 spin_lock_init(&conn->lock);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001088 mutex_init(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001089
1090 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001092 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001093 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001094 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001095 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001096
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001097 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001098
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 return conn;
1100}
1101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104/* Find socket with psm and source bdaddr.
1105 * Returns closest match.
1106 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001107static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001109 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001111 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001112
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001113 list_for_each_entry(c, &chan_list, global_l) {
1114 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001115
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001116 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 continue;
1118
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001119 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001121 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001122 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001123 return c;
1124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126 /* Closest match */
1127 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001128 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 }
1130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001132 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001133
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001134 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135}
1136
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001137int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001139 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 struct l2cap_conn *conn;
1142 struct hci_conn *hcon;
1143 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001144 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001145 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001147 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001148 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001150 hdev = hci_get_route(dst, src);
1151 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 return -EHOSTUNREACH;
1153
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001154 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001156 l2cap_chan_lock(chan);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001157
1158 /* PSM must be odd and lsb of upper byte must be 0 */
1159 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1160 chan->chan_type != L2CAP_CHAN_RAW) {
1161 err = -EINVAL;
1162 goto done;
1163 }
1164
1165 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1166 err = -EINVAL;
1167 goto done;
1168 }
1169
1170 switch (chan->mode) {
1171 case L2CAP_MODE_BASIC:
1172 break;
1173 case L2CAP_MODE_ERTM:
1174 case L2CAP_MODE_STREAMING:
1175 if (!disable_ertm)
1176 break;
1177 /* fall through */
1178 default:
1179 err = -ENOTSUPP;
1180 goto done;
1181 }
1182
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001183 lock_sock(sk);
1184
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001185 switch (sk->sk_state) {
1186 case BT_CONNECT:
1187 case BT_CONNECT2:
1188 case BT_CONFIG:
1189 /* Already connecting */
1190 err = 0;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001191 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001192 goto done;
1193
1194 case BT_CONNECTED:
1195 /* Already connected */
1196 err = -EISCONN;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001197 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001198 goto done;
1199
1200 case BT_OPEN:
1201 case BT_BOUND:
1202 /* Can connect */
1203 break;
1204
1205 default:
1206 err = -EBADFD;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001207 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001208 goto done;
1209 }
1210
1211 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001212 bacpy(&bt_sk(sk)->dst, dst);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001213
1214 release_sock(sk);
1215
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001216 chan->psm = psm;
1217 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001219 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001220
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001221 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001222 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001223 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001224 else
1225 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001226 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001227
Ville Tervo30e76272011-02-22 16:10:53 -03001228 if (IS_ERR(hcon)) {
1229 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 conn = l2cap_conn_add(hcon, 0);
1234 if (!conn) {
1235 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001236 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 goto done;
1238 }
1239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 /* Update source addr of the socket */
1241 bacpy(src, conn->src);
1242
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001243 l2cap_chan_unlock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001244 l2cap_chan_add(conn, chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001245 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001246
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001247 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001248 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001251 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001252 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001253 if (l2cap_chan_check_security(chan))
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001254 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001255 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001256 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 }
1258
Ville Tervo30e76272011-02-22 16:10:53 -03001259 err = 0;
1260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001262 l2cap_chan_unlock(chan);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001263 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 hci_dev_put(hdev);
1265 return err;
1266}
1267
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001268int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001269{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001270 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001271 DECLARE_WAITQUEUE(wait, current);
1272 int err = 0;
1273 int timeo = HZ/5;
1274
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001275 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001276 set_current_state(TASK_INTERRUPTIBLE);
1277 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001278 if (!timeo)
1279 timeo = HZ/5;
1280
1281 if (signal_pending(current)) {
1282 err = sock_intr_errno(timeo);
1283 break;
1284 }
1285
1286 release_sock(sk);
1287 timeo = schedule_timeout(timeo);
1288 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001289 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001290
1291 err = sock_error(sk);
1292 if (err)
1293 break;
1294 }
1295 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001296 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001297 return err;
1298}
1299
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001300static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001301{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001302 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1303 monitor_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001304
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001305 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001306
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001307 l2cap_chan_lock(chan);
1308
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001309 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001310 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001311 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001312 return;
1313 }
1314
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001315 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001316 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001317
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001318 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001319 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001320}
1321
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001322static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001323{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001324 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1325 retrans_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001326
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001327 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001328
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001329 l2cap_chan_lock(chan);
1330
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001331 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001332 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001333
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001334 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001335
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001336 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001337
1338 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001339}
1340
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001341static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001342{
1343 struct sk_buff *skb;
1344
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001345 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001346 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001347 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001348 break;
1349
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001350 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001351 kfree_skb(skb);
1352
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001353 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001354 }
1355
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001356 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001357 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001358}
1359
Szymon Janc67c9e842011-07-28 16:24:33 +02001360static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001361{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001362 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001363 u32 control;
1364 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001365
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001366 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001367 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001368 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001369 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001370
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001371 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001372 fcs = crc16(0, (u8 *)skb->data,
1373 skb->len - L2CAP_FCS_SIZE);
1374 put_unaligned_le16(fcs,
1375 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001376 }
1377
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001378 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001379
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001380 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001381 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001382}
1383
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001384static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001385{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001386 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001387 u16 fcs;
1388 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001389
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001390 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001391 if (!skb)
1392 return;
1393
Szymon Jancd1726b62011-11-16 09:32:20 +01001394 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001395 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001396 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001397
Szymon Jancd1726b62011-11-16 09:32:20 +01001398 skb = skb_queue_next(&chan->tx_q, skb);
1399 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001400
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001401 if (chan->remote_max_tx &&
1402 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001403 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001404 return;
1405 }
1406
1407 tx_skb = skb_clone(skb, GFP_ATOMIC);
1408 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001409
1410 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001411 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001412
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001413 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001414 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001415
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001416 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001417 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001418
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001419 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001420
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001421 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001422 fcs = crc16(0, (u8 *)tx_skb->data,
1423 tx_skb->len - L2CAP_FCS_SIZE);
1424 put_unaligned_le16(fcs,
1425 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001426 }
1427
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001428 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001429}
1430
Szymon Janc67c9e842011-07-28 16:24:33 +02001431static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001432{
1433 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001434 u16 fcs;
1435 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001436 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001437
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001438 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001439 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001440
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001441 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001442
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001443 if (chan->remote_max_tx &&
1444 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001445 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001446 break;
1447 }
1448
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001449 tx_skb = skb_clone(skb, GFP_ATOMIC);
1450
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001451 bt_cb(skb)->retries++;
1452
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001453 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001454 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001455
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001456 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001457 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001458
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001459 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001460 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001461
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001462 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001463
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001464 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001465 fcs = crc16(0, (u8 *)skb->data,
1466 tx_skb->len - L2CAP_FCS_SIZE);
1467 put_unaligned_le16(fcs, skb->data +
1468 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001469 }
1470
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001471 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001472
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001473 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001474
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001475 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001476
1477 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001478
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001479 if (bt_cb(skb)->retries == 1) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001480 chan->unacked_frames++;
Szymon Janc930fa4a2012-02-07 15:43:02 +01001481
1482 if (!nsent++)
1483 __clear_ack_timer(chan);
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001484 }
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301485
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001486 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001487
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001488 if (skb_queue_is_last(&chan->tx_q, skb))
1489 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001490 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001491 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001492 }
1493
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001494 return nsent;
1495}
1496
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001497static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001498{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001499 int ret;
1500
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001501 if (!skb_queue_empty(&chan->tx_q))
1502 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001503
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001504 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001505 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001506 return ret;
1507}
1508
Szymon Jancb17e73b2012-01-11 10:59:47 +01001509static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001510{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001511 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001512
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001513 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001514
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001515 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001516 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001517 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001518 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001519 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001520 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001521
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001522 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001523 return;
1524
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001525 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001526 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001527}
1528
Szymon Jancb17e73b2012-01-11 10:59:47 +01001529static void l2cap_send_ack(struct l2cap_chan *chan)
1530{
1531 __clear_ack_timer(chan);
1532 __l2cap_send_ack(chan);
1533}
1534
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001535static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001536{
1537 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001538 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001539
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001540 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001541 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001542
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001543 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001544 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001545
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001546 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001547}
1548
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001549static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
1550 struct msghdr *msg, int len,
1551 int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001553 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001554 struct sk_buff **frag;
1555 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001557 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001558 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
1560 sent += count;
1561 len -= count;
1562
1563 /* Continuation fragments (no L2CAP header) */
1564 frag = &skb_shinfo(skb)->frag_list;
1565 while (len) {
1566 count = min_t(unsigned int, conn->mtu, len);
1567
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001568 *frag = chan->ops->alloc_skb(chan, count,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001569 msg->msg_flags & MSG_DONTWAIT,
1570 &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001571
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001573 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001574 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1575 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001577 (*frag)->priority = skb->priority;
1578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 sent += count;
1580 len -= count;
1581
1582 frag = &(*frag)->next;
1583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
1585 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001586}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001588static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1589 struct msghdr *msg, size_t len,
1590 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001591{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001592 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001593 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001594 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001595 struct l2cap_hdr *lh;
1596
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001597 BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001598
1599 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001600
1601 skb = chan->ops->alloc_skb(chan, count + hlen,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001602 msg->msg_flags & MSG_DONTWAIT, &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001603
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001604 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001605 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001606
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001607 skb->priority = priority;
1608
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001609 /* Create L2CAP header */
1610 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001611 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001612 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001613 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001614
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001615 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001616 if (unlikely(err < 0)) {
1617 kfree_skb(skb);
1618 return ERR_PTR(err);
1619 }
1620 return skb;
1621}
1622
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001623static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1624 struct msghdr *msg, size_t len,
1625 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001626{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001627 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001628 struct sk_buff *skb;
1629 int err, count, hlen = L2CAP_HDR_SIZE;
1630 struct l2cap_hdr *lh;
1631
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001632 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001633
1634 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001635
1636 skb = chan->ops->alloc_skb(chan, count + hlen,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001637 msg->msg_flags & MSG_DONTWAIT, &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001638
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001639 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001640 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001641
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001642 skb->priority = priority;
1643
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001644 /* Create L2CAP header */
1645 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001646 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001647 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1648
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001649 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001650 if (unlikely(err < 0)) {
1651 kfree_skb(skb);
1652 return ERR_PTR(err);
1653 }
1654 return skb;
1655}
1656
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001657static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1658 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001659 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001660{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001661 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001662 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001663 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001664 struct l2cap_hdr *lh;
1665
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001666 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001667
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001668 if (!conn)
1669 return ERR_PTR(-ENOTCONN);
1670
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001671 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1672 hlen = L2CAP_EXT_HDR_SIZE;
1673 else
1674 hlen = L2CAP_ENH_HDR_SIZE;
1675
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001676 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001677 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001678
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001679 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001680 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001681
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001682 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001683
1684 skb = chan->ops->alloc_skb(chan, count + hlen,
1685 msg->msg_flags & MSG_DONTWAIT, &err);
1686
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001687 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001688 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001689
1690 /* Create L2CAP header */
1691 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001692 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001693 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001694
1695 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1696
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001697 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001698 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001699
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001700 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001701 if (unlikely(err < 0)) {
1702 kfree_skb(skb);
1703 return ERR_PTR(err);
1704 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001705
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001706 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001707 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001708
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001709 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001710 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711}
1712
Szymon Janc67c9e842011-07-28 16:24:33 +02001713static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001714{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001715 struct sk_buff *skb;
1716 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001717 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001718 size_t size = 0;
1719
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001720 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001721 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001722 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001723 if (IS_ERR(skb))
1724 return PTR_ERR(skb);
1725
1726 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001727 len -= chan->remote_mps;
1728 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001729
1730 while (len > 0) {
1731 size_t buflen;
1732
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001733 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001734 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001735 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001736 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001737 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001738 buflen = len;
1739 }
1740
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001741 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001742 if (IS_ERR(skb)) {
1743 skb_queue_purge(&sar_queue);
1744 return PTR_ERR(skb);
1745 }
1746
1747 __skb_queue_tail(&sar_queue, skb);
1748 len -= buflen;
1749 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001750 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001751 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1752 if (chan->tx_send_head == NULL)
1753 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001754
1755 return size;
1756}
1757
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001758int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1759 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001760{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001761 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001762 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001763 int err;
1764
1765 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001766 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001767 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001768 if (IS_ERR(skb))
1769 return PTR_ERR(skb);
1770
1771 l2cap_do_send(chan, skb);
1772 return len;
1773 }
1774
1775 switch (chan->mode) {
1776 case L2CAP_MODE_BASIC:
1777 /* Check outgoing MTU */
1778 if (len > chan->omtu)
1779 return -EMSGSIZE;
1780
1781 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001782 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001783 if (IS_ERR(skb))
1784 return PTR_ERR(skb);
1785
1786 l2cap_do_send(chan, skb);
1787 err = len;
1788 break;
1789
1790 case L2CAP_MODE_ERTM:
1791 case L2CAP_MODE_STREAMING:
1792 /* Entire SDU fits into one PDU */
1793 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001794 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001795 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1796 0);
1797 if (IS_ERR(skb))
1798 return PTR_ERR(skb);
1799
1800 __skb_queue_tail(&chan->tx_q, skb);
1801
1802 if (chan->tx_send_head == NULL)
1803 chan->tx_send_head = skb;
1804
1805 } else {
1806 /* Segment SDU into multiples PDUs */
1807 err = l2cap_sar_segment_sdu(chan, msg, len);
1808 if (err < 0)
1809 return err;
1810 }
1811
1812 if (chan->mode == L2CAP_MODE_STREAMING) {
1813 l2cap_streaming_send(chan);
1814 err = len;
1815 break;
1816 }
1817
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001818 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1819 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001820 err = len;
1821 break;
1822 }
1823
1824 err = l2cap_ertm_send(chan);
1825 if (err >= 0)
1826 err = len;
1827
1828 break;
1829
1830 default:
1831 BT_DBG("bad state %1.1x", chan->mode);
1832 err = -EBADFD;
1833 }
1834
1835 return err;
1836}
1837
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838/* Copy frame to all raw sockets on that connection */
1839static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1840{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001842 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844 BT_DBG("conn %p", conn);
1845
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001846 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001847
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001848 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001849 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001850 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 continue;
1852
1853 /* Don't send frame to the socket it came from */
1854 if (skb->sk == sk)
1855 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001856 nskb = skb_clone(skb, GFP_ATOMIC);
1857 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 continue;
1859
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001860 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 kfree_skb(nskb);
1862 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001863
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001864 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865}
1866
1867/* ---- L2CAP signalling commands ---- */
1868static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1869 u8 code, u8 ident, u16 dlen, void *data)
1870{
1871 struct sk_buff *skb, **frag;
1872 struct l2cap_cmd_hdr *cmd;
1873 struct l2cap_hdr *lh;
1874 int len, count;
1875
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001876 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1877 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
1879 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1880 count = min_t(unsigned int, conn->mtu, len);
1881
1882 skb = bt_skb_alloc(count, GFP_ATOMIC);
1883 if (!skb)
1884 return NULL;
1885
1886 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001887 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001888
1889 if (conn->hcon->type == LE_LINK)
1890 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1891 else
1892 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
1894 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1895 cmd->code = code;
1896 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001897 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899 if (dlen) {
1900 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1901 memcpy(skb_put(skb, count), data, count);
1902 data += count;
1903 }
1904
1905 len -= skb->len;
1906
1907 /* Continuation fragments (no L2CAP header) */
1908 frag = &skb_shinfo(skb)->frag_list;
1909 while (len) {
1910 count = min_t(unsigned int, conn->mtu, len);
1911
1912 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1913 if (!*frag)
1914 goto fail;
1915
1916 memcpy(skb_put(*frag, count), data, count);
1917
1918 len -= count;
1919 data += count;
1920
1921 frag = &(*frag)->next;
1922 }
1923
1924 return skb;
1925
1926fail:
1927 kfree_skb(skb);
1928 return NULL;
1929}
1930
1931static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1932{
1933 struct l2cap_conf_opt *opt = *ptr;
1934 int len;
1935
1936 len = L2CAP_CONF_OPT_SIZE + opt->len;
1937 *ptr += len;
1938
1939 *type = opt->type;
1940 *olen = opt->len;
1941
1942 switch (opt->len) {
1943 case 1:
1944 *val = *((u8 *) opt->val);
1945 break;
1946
1947 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001948 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 break;
1950
1951 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001952 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 break;
1954
1955 default:
1956 *val = (unsigned long) opt->val;
1957 break;
1958 }
1959
1960 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1961 return len;
1962}
1963
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1965{
1966 struct l2cap_conf_opt *opt = *ptr;
1967
1968 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1969
1970 opt->type = type;
1971 opt->len = len;
1972
1973 switch (len) {
1974 case 1:
1975 *((u8 *) opt->val) = val;
1976 break;
1977
1978 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001979 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 break;
1981
1982 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001983 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 break;
1985
1986 default:
1987 memcpy(opt->val, (void *) val, len);
1988 break;
1989 }
1990
1991 *ptr += L2CAP_CONF_OPT_SIZE + len;
1992}
1993
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001994static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1995{
1996 struct l2cap_conf_efs efs;
1997
Szymon Janc1ec918c2011-11-16 09:32:21 +01001998 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001999 case L2CAP_MODE_ERTM:
2000 efs.id = chan->local_id;
2001 efs.stype = chan->local_stype;
2002 efs.msdu = cpu_to_le16(chan->local_msdu);
2003 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2004 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
2005 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
2006 break;
2007
2008 case L2CAP_MODE_STREAMING:
2009 efs.id = 1;
2010 efs.stype = L2CAP_SERV_BESTEFFORT;
2011 efs.msdu = cpu_to_le16(chan->local_msdu);
2012 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2013 efs.acc_lat = 0;
2014 efs.flush_to = 0;
2015 break;
2016
2017 default:
2018 return;
2019 }
2020
2021 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
2022 (unsigned long) &efs);
2023}
2024
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002025static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002026{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002027 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2028 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002029
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02002030 BT_DBG("chan %p", chan);
2031
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002032 l2cap_chan_lock(chan);
2033
Szymon Jancb17e73b2012-01-11 10:59:47 +01002034 __l2cap_send_ack(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002035
2036 l2cap_chan_unlock(chan);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002037
2038 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002039}
2040
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002041static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002042{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002043 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002044 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002045 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002046 chan->num_acked = 0;
2047 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002048
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002049 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2050 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2051 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002052
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002053 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002054
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002055 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002056}
2057
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002058static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2059{
2060 switch (mode) {
2061 case L2CAP_MODE_STREAMING:
2062 case L2CAP_MODE_ERTM:
2063 if (l2cap_mode_supported(mode, remote_feat_mask))
2064 return mode;
2065 /* fall through */
2066 default:
2067 return L2CAP_MODE_BASIC;
2068 }
2069}
2070
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002071static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2072{
2073 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2074}
2075
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002076static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2077{
2078 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2079}
2080
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002081static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2082{
2083 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002084 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002085 /* use extended control field */
2086 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002087 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2088 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002089 chan->tx_win = min_t(u16, chan->tx_win,
2090 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002091 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2092 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002093}
2094
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002095static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002098 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002100 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002102 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002104 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002105 goto done;
2106
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002107 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002108 case L2CAP_MODE_STREAMING:
2109 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002110 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002111 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002112
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002113 if (__l2cap_efs_supported(chan))
2114 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2115
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002116 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002117 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002118 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002119 break;
2120 }
2121
2122done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002123 if (chan->imtu != L2CAP_DEFAULT_MTU)
2124 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002125
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002126 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002127 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002128 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2129 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002130 break;
2131
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002132 rfc.mode = L2CAP_MODE_BASIC;
2133 rfc.txwin_size = 0;
2134 rfc.max_transmit = 0;
2135 rfc.retrans_timeout = 0;
2136 rfc.monitor_timeout = 0;
2137 rfc.max_pdu_size = 0;
2138
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002139 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2140 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002141 break;
2142
2143 case L2CAP_MODE_ERTM:
2144 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002145 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002146 rfc.retrans_timeout = 0;
2147 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002148
2149 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2150 L2CAP_EXT_HDR_SIZE -
2151 L2CAP_SDULEN_SIZE -
2152 L2CAP_FCS_SIZE);
2153 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002154
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002155 l2cap_txwin_setup(chan);
2156
2157 rfc.txwin_size = min_t(u16, chan->tx_win,
2158 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002159
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002160 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2161 (unsigned long) &rfc);
2162
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002163 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2164 l2cap_add_opt_efs(&ptr, chan);
2165
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002166 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002167 break;
2168
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002169 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002170 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002171 chan->fcs = L2CAP_FCS_NONE;
2172 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002173 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002174
2175 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2176 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2177 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002178 break;
2179
2180 case L2CAP_MODE_STREAMING:
2181 rfc.mode = L2CAP_MODE_STREAMING;
2182 rfc.txwin_size = 0;
2183 rfc.max_transmit = 0;
2184 rfc.retrans_timeout = 0;
2185 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002186
2187 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2188 L2CAP_EXT_HDR_SIZE -
2189 L2CAP_SDULEN_SIZE -
2190 L2CAP_FCS_SIZE);
2191 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002192
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002193 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2194 (unsigned long) &rfc);
2195
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002196 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2197 l2cap_add_opt_efs(&ptr, chan);
2198
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002199 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002200 break;
2201
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002202 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002203 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002204 chan->fcs = L2CAP_FCS_NONE;
2205 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002206 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002207 break;
2208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002210 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002211 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
2213 return ptr - data;
2214}
2215
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002216static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002218 struct l2cap_conf_rsp *rsp = data;
2219 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002220 void *req = chan->conf_req;
2221 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002222 int type, hint, olen;
2223 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002224 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002225 struct l2cap_conf_efs efs;
2226 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002227 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002228 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002229 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002231 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002232
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002233 while (len >= L2CAP_CONF_OPT_SIZE) {
2234 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002236 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002237 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002238
2239 switch (type) {
2240 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002241 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002242 break;
2243
2244 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002245 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002246 break;
2247
2248 case L2CAP_CONF_QOS:
2249 break;
2250
Marcel Holtmann6464f352007-10-20 13:39:51 +02002251 case L2CAP_CONF_RFC:
2252 if (olen == sizeof(rfc))
2253 memcpy(&rfc, (void *) val, olen);
2254 break;
2255
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002256 case L2CAP_CONF_FCS:
2257 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002258 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002259 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002260
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002261 case L2CAP_CONF_EFS:
2262 remote_efs = 1;
2263 if (olen == sizeof(efs))
2264 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002265 break;
2266
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002267 case L2CAP_CONF_EWS:
2268 if (!enable_hs)
2269 return -ECONNREFUSED;
2270
2271 set_bit(FLAG_EXT_CTRL, &chan->flags);
2272 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002273 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002274 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002275 break;
2276
2277 default:
2278 if (hint)
2279 break;
2280
2281 result = L2CAP_CONF_UNKNOWN;
2282 *((u8 *) ptr++) = type;
2283 break;
2284 }
2285 }
2286
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002287 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002288 goto done;
2289
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002290 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002291 case L2CAP_MODE_STREAMING:
2292 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002293 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002294 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002295 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002296 break;
2297 }
2298
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002299 if (remote_efs) {
2300 if (__l2cap_efs_supported(chan))
2301 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2302 else
2303 return -ECONNREFUSED;
2304 }
2305
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002306 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002307 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002308
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002309 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002310 }
2311
2312done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002313 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002314 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002315 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002316
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002317 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002318 return -ECONNREFUSED;
2319
2320 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2321 sizeof(rfc), (unsigned long) &rfc);
2322 }
2323
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002324 if (result == L2CAP_CONF_SUCCESS) {
2325 /* Configure output options and let the other side know
2326 * which ones we don't like. */
2327
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002328 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2329 result = L2CAP_CONF_UNACCEPT;
2330 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002331 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002332 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002333 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002334 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002335
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002336 if (remote_efs) {
2337 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2338 efs.stype != L2CAP_SERV_NOTRAFIC &&
2339 efs.stype != chan->local_stype) {
2340
2341 result = L2CAP_CONF_UNACCEPT;
2342
2343 if (chan->num_conf_req >= 1)
2344 return -ECONNREFUSED;
2345
2346 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002347 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002348 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002349 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002350 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002351 result = L2CAP_CONF_PENDING;
2352 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002353 }
2354 }
2355
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002356 switch (rfc.mode) {
2357 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002358 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002359 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002360 break;
2361
2362 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002363 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2364 chan->remote_tx_win = rfc.txwin_size;
2365 else
2366 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2367
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002368 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002369
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002370 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2371 chan->conn->mtu -
2372 L2CAP_EXT_HDR_SIZE -
2373 L2CAP_SDULEN_SIZE -
2374 L2CAP_FCS_SIZE);
2375 rfc.max_pdu_size = cpu_to_le16(size);
2376 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002377
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002378 rfc.retrans_timeout =
2379 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2380 rfc.monitor_timeout =
2381 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002382
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002383 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002384
2385 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2386 sizeof(rfc), (unsigned long) &rfc);
2387
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002388 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2389 chan->remote_id = efs.id;
2390 chan->remote_stype = efs.stype;
2391 chan->remote_msdu = le16_to_cpu(efs.msdu);
2392 chan->remote_flush_to =
2393 le32_to_cpu(efs.flush_to);
2394 chan->remote_acc_lat =
2395 le32_to_cpu(efs.acc_lat);
2396 chan->remote_sdu_itime =
2397 le32_to_cpu(efs.sdu_itime);
2398 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2399 sizeof(efs), (unsigned long) &efs);
2400 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002401 break;
2402
2403 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002404 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2405 chan->conn->mtu -
2406 L2CAP_EXT_HDR_SIZE -
2407 L2CAP_SDULEN_SIZE -
2408 L2CAP_FCS_SIZE);
2409 rfc.max_pdu_size = cpu_to_le16(size);
2410 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002411
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002412 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002413
2414 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2415 sizeof(rfc), (unsigned long) &rfc);
2416
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002417 break;
2418
2419 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002420 result = L2CAP_CONF_UNACCEPT;
2421
2422 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002423 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002424 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002425
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002426 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002427 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002428 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002429 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002430 rsp->result = cpu_to_le16(result);
2431 rsp->flags = cpu_to_le16(0x0000);
2432
2433 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434}
2435
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002436static 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 -03002437{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002438 struct l2cap_conf_req *req = data;
2439 void *ptr = req->data;
2440 int type, olen;
2441 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002442 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002443 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002444
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002445 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002446
2447 while (len >= L2CAP_CONF_OPT_SIZE) {
2448 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2449
2450 switch (type) {
2451 case L2CAP_CONF_MTU:
2452 if (val < L2CAP_DEFAULT_MIN_MTU) {
2453 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002454 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002455 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002456 chan->imtu = val;
2457 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002458 break;
2459
2460 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002461 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002462 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002463 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002464 break;
2465
2466 case L2CAP_CONF_RFC:
2467 if (olen == sizeof(rfc))
2468 memcpy(&rfc, (void *)val, olen);
2469
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002470 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002471 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002472 return -ECONNREFUSED;
2473
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002474 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002475
2476 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2477 sizeof(rfc), (unsigned long) &rfc);
2478 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002479
2480 case L2CAP_CONF_EWS:
2481 chan->tx_win = min_t(u16, val,
2482 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002483 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2484 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002485 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002486
2487 case L2CAP_CONF_EFS:
2488 if (olen == sizeof(efs))
2489 memcpy(&efs, (void *)val, olen);
2490
2491 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2492 efs.stype != L2CAP_SERV_NOTRAFIC &&
2493 efs.stype != chan->local_stype)
2494 return -ECONNREFUSED;
2495
2496 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2497 sizeof(efs), (unsigned long) &efs);
2498 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002499 }
2500 }
2501
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002502 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002503 return -ECONNREFUSED;
2504
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002505 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002506
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002507 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002508 switch (rfc.mode) {
2509 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002510 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2511 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2512 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002513
2514 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2515 chan->local_msdu = le16_to_cpu(efs.msdu);
2516 chan->local_sdu_itime =
2517 le32_to_cpu(efs.sdu_itime);
2518 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2519 chan->local_flush_to =
2520 le32_to_cpu(efs.flush_to);
2521 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002522 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002523
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002524 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002525 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002526 }
2527 }
2528
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002529 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002530 req->flags = cpu_to_le16(0x0000);
2531
2532 return ptr - data;
2533}
2534
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002535static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536{
2537 struct l2cap_conf_rsp *rsp = data;
2538 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002540 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002542 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002543 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002544 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545
2546 return ptr - data;
2547}
2548
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002549void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002550{
2551 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002552 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002553 u8 buf[128];
2554
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002555 rsp.scid = cpu_to_le16(chan->dcid);
2556 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002557 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2558 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2559 l2cap_send_cmd(conn, chan->ident,
2560 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2561
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002562 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002563 return;
2564
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002565 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2566 l2cap_build_conf_req(chan, buf), buf);
2567 chan->num_conf_req++;
2568}
2569
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002570static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002571{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002572 int type, olen;
2573 unsigned long val;
2574 struct l2cap_conf_rfc rfc;
2575
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002576 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002577
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002578 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002579 return;
2580
2581 while (len >= L2CAP_CONF_OPT_SIZE) {
2582 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2583
2584 switch (type) {
2585 case L2CAP_CONF_RFC:
2586 if (olen == sizeof(rfc))
2587 memcpy(&rfc, (void *)val, olen);
2588 goto done;
2589 }
2590 }
2591
Mat Martineau36e999a2011-12-08 17:23:21 -08002592 /* Use sane default values in case a misbehaving remote device
2593 * did not send an RFC option.
2594 */
2595 rfc.mode = chan->mode;
2596 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2597 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2598 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2599
2600 BT_ERR("Expected RFC option was not found, using defaults");
2601
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002602done:
2603 switch (rfc.mode) {
2604 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002605 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2606 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2607 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002608 break;
2609 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002610 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002611 }
2612}
2613
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002614static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2615{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002616 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002617
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002618 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002619 return 0;
2620
2621 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2622 cmd->ident == conn->info_ident) {
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02002623 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002624
2625 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002626 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002627
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002628 l2cap_conn_start(conn);
2629 }
2630
2631 return 0;
2632}
2633
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2635{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2637 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002638 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002639 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002640 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641
2642 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002643 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
2645 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2646
2647 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002648 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2649 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 result = L2CAP_CR_BAD_PSM;
2651 goto sendresp;
2652 }
2653
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002654 parent = pchan->sk;
2655
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002656 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002657 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002658
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002659 /* Check if the ACL is secure enough (if not SDP) */
2660 if (psm != cpu_to_le16(0x0001) &&
2661 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002662 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002663 result = L2CAP_CR_SEC_BLOCK;
2664 goto response;
2665 }
2666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 result = L2CAP_CR_NO_MEM;
2668
2669 /* Check for backlog size */
2670 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002671 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 goto response;
2673 }
2674
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002675 chan = pchan->ops->new_connection(pchan->data);
2676 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 goto response;
2678
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002679 sk = chan->sk;
2680
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002682 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002684 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 goto response;
2686 }
2687
2688 hci_conn_hold(conn->hcon);
2689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 bacpy(&bt_sk(sk)->src, conn->src);
2691 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002692 chan->psm = psm;
2693 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002695 bt_accept_enqueue(parent, sk);
2696
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002697 __l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002698
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002699 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002701 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002703 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Marcel Holtmann984947d2009-02-06 23:35:19 +01002705 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002706 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002707 if (bt_sk(sk)->defer_setup) {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002708 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002709 result = L2CAP_CR_PEND;
2710 status = L2CAP_CS_AUTHOR_PEND;
2711 parent->sk_data_ready(parent, 0);
2712 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002713 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002714 result = L2CAP_CR_SUCCESS;
2715 status = L2CAP_CS_NO_INFO;
2716 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002717 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002718 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002719 result = L2CAP_CR_PEND;
2720 status = L2CAP_CS_AUTHEN_PEND;
2721 }
2722 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002723 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002724 result = L2CAP_CR_PEND;
2725 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 }
2727
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002729 release_sock(parent);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002730 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731
2732sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002733 rsp.scid = cpu_to_le16(scid);
2734 rsp.dcid = cpu_to_le16(dcid);
2735 rsp.result = cpu_to_le16(result);
2736 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002738
2739 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2740 struct l2cap_info_req info;
2741 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2742
2743 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2744 conn->info_ident = l2cap_get_ident(conn);
2745
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08002746 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002747
2748 l2cap_send_cmd(conn, conn->info_ident,
2749 L2CAP_INFO_REQ, sizeof(info), &info);
2750 }
2751
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002752 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002753 result == L2CAP_CR_SUCCESS) {
2754 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002755 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002756 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002757 l2cap_build_conf_req(chan, buf), buf);
2758 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002759 }
2760
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 return 0;
2762}
2763
2764static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2765{
2766 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2767 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002768 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 u8 req[128];
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002770 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771
2772 scid = __le16_to_cpu(rsp->scid);
2773 dcid = __le16_to_cpu(rsp->dcid);
2774 result = __le16_to_cpu(rsp->result);
2775 status = __le16_to_cpu(rsp->status);
2776
Andrei Emeltchenko1b009c92012-02-21 12:54:54 +02002777 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
2778 dcid, scid, result, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002780 mutex_lock(&conn->chan_lock);
2781
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 if (scid) {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002783 chan = __l2cap_get_chan_by_scid(conn, scid);
2784 if (!chan) {
2785 err = -EFAULT;
2786 goto unlock;
2787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 } else {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002789 chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
2790 if (!chan) {
2791 err = -EFAULT;
2792 goto unlock;
2793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 }
2795
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002796 err = 0;
2797
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002798 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002799
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 switch (result) {
2801 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002802 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002803 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002804 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002805 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002806
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002807 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002808 break;
2809
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002811 l2cap_build_conf_req(chan, req), req);
2812 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 break;
2814
2815 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002816 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 break;
2818
2819 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002820 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 break;
2822 }
2823
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002824 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002825
2826unlock:
2827 mutex_unlock(&conn->chan_lock);
2828
2829 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830}
2831
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002832static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002833{
2834 /* FCS is enabled only in ERTM or streaming mode, if one or both
2835 * sides request it.
2836 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002837 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002838 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002839 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002840 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002841}
2842
Al Viro88219a02007-07-29 00:17:25 -07002843static 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 -07002844{
2845 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2846 u16 dcid, flags;
2847 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002848 struct l2cap_chan *chan;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002849 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
2851 dcid = __le16_to_cpu(req->dcid);
2852 flags = __le16_to_cpu(req->flags);
2853
2854 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2855
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002856 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002857 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 return -ENOENT;
2859
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002860 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002861
David S. Miller033b1142011-07-21 13:38:42 -07002862 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002863 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002864
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002865 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2866 rej.scid = cpu_to_le16(chan->scid);
2867 rej.dcid = cpu_to_le16(chan->dcid);
2868
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002869 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2870 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002871 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002872 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002873
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002874 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002875 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002876 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002877 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002878 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002879 L2CAP_CONF_REJECT, flags), rsp);
2880 goto unlock;
2881 }
2882
2883 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002884 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2885 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
2887 if (flags & 0x0001) {
2888 /* Incomplete config. Send empty response. */
2889 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002890 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002891 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 goto unlock;
2893 }
2894
2895 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002896 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002897 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002898 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002902 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002903 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002904
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002905 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002906 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002907
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002908 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002909 goto unlock;
2910
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002911 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002912 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002913
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002914 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002915
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002916 chan->next_tx_seq = 0;
2917 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002918 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002919 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002920 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002921
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02002922 l2cap_chan_ready(chan);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002923 goto unlock;
2924 }
2925
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002926 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002927 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002929 l2cap_build_conf_req(chan, buf), buf);
2930 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 }
2932
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002933 /* Got Conf Rsp PENDING from remote side and asume we sent
2934 Conf Rsp PENDING in the code above */
2935 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2936 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2937
2938 /* check compatibility */
2939
2940 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2941 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2942
2943 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002944 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002945 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2946 }
2947
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948unlock:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002949 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 return 0;
2951}
2952
2953static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2954{
2955 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2956 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002957 struct l2cap_chan *chan;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002958 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
2960 scid = __le16_to_cpu(rsp->scid);
2961 flags = __le16_to_cpu(rsp->flags);
2962 result = __le16_to_cpu(rsp->result);
2963
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002964 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2965 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002967 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002968 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 return 0;
2970
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002971 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002972
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 switch (result) {
2974 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002975 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002976 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 break;
2978
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002979 case L2CAP_CONF_PENDING:
2980 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2981
2982 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2983 char buf[64];
2984
2985 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2986 buf, &result);
2987 if (len < 0) {
2988 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2989 goto done;
2990 }
2991
2992 /* check compatibility */
2993
2994 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2995 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2996
2997 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002998 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002999 L2CAP_CONF_SUCCESS, 0x0000), buf);
3000 }
3001 goto done;
3002
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003004 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003005 char req[64];
3006
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003007 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003008 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003009 goto done;
3010 }
3011
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003012 /* throw out any old stored conf requests */
3013 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03003014 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
3015 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003016 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003017 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003018 goto done;
3019 }
3020
3021 l2cap_send_cmd(conn, l2cap_get_ident(conn),
3022 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003023 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003024 if (result != L2CAP_CONF_SUCCESS)
3025 goto done;
3026 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 }
3028
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09003029 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003030 l2cap_chan_set_err(chan, ECONNRESET);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +02003031
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08003032 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003033 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 goto done;
3035 }
3036
3037 if (flags & 0x01)
3038 goto done;
3039
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003040 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003042 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003043 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003044
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003045 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003046 chan->next_tx_seq = 0;
3047 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003048 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003049 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003050 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003051
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02003052 l2cap_chan_ready(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 }
3054
3055done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003056 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 return 0;
3058}
3059
3060static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3061{
3062 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3063 struct l2cap_disconn_rsp rsp;
3064 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003065 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 struct sock *sk;
3067
3068 scid = __le16_to_cpu(req->scid);
3069 dcid = __le16_to_cpu(req->dcid);
3070
3071 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3072
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003073 mutex_lock(&conn->chan_lock);
3074
3075 chan = __l2cap_get_chan_by_scid(conn, dcid);
3076 if (!chan) {
3077 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003081 l2cap_chan_lock(chan);
3082
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003083 sk = chan->sk;
3084
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003085 rsp.dcid = cpu_to_le16(chan->scid);
3086 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3088
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003089 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 sk->sk_shutdown = SHUTDOWN_MASK;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003091 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003093 l2cap_chan_del(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003094
3095 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003097 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003098
3099 mutex_unlock(&conn->chan_lock);
3100
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 return 0;
3102}
3103
3104static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3105{
3106 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3107 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003108 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110 scid = __le16_to_cpu(rsp->scid);
3111 dcid = __le16_to_cpu(rsp->dcid);
3112
3113 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3114
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003115 mutex_lock(&conn->chan_lock);
3116
3117 chan = __l2cap_get_chan_by_scid(conn, scid);
3118 if (!chan) {
3119 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003123 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003124
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003125 l2cap_chan_del(chan, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003126
3127 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003129 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003130
3131 mutex_unlock(&conn->chan_lock);
3132
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 return 0;
3134}
3135
3136static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3137{
3138 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 u16 type;
3140
3141 type = __le16_to_cpu(req->type);
3142
3143 BT_DBG("type 0x%4.4x", type);
3144
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003145 if (type == L2CAP_IT_FEAT_MASK) {
3146 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003147 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003148 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3149 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3150 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003151 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003152 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3153 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003154 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003155 feat_mask |= L2CAP_FEAT_EXT_FLOW
3156 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003157
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003158 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003159 l2cap_send_cmd(conn, cmd->ident,
3160 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003161 } else if (type == L2CAP_IT_FIXED_CHAN) {
3162 u8 buf[12];
3163 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003164
3165 if (enable_hs)
3166 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3167 else
3168 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3169
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003170 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3171 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003172 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003173 l2cap_send_cmd(conn, cmd->ident,
3174 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003175 } else {
3176 struct l2cap_info_rsp rsp;
3177 rsp.type = cpu_to_le16(type);
3178 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3179 l2cap_send_cmd(conn, cmd->ident,
3180 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
3183 return 0;
3184}
3185
3186static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3187{
3188 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3189 u16 type, result;
3190
3191 type = __le16_to_cpu(rsp->type);
3192 result = __le16_to_cpu(rsp->result);
3193
3194 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3195
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003196 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3197 if (cmd->ident != conn->info_ident ||
3198 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3199 return 0;
3200
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02003201 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003202
Ville Tervoadb08ed2010-08-04 09:43:33 +03003203 if (result != L2CAP_IR_SUCCESS) {
3204 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3205 conn->info_ident = 0;
3206
3207 l2cap_conn_start(conn);
3208
3209 return 0;
3210 }
3211
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003212 switch (type) {
3213 case L2CAP_IT_FEAT_MASK:
Harvey Harrison83985312008-05-02 16:25:46 -07003214 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003215
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003216 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003217 struct l2cap_info_req req;
3218 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3219
3220 conn->info_ident = l2cap_get_ident(conn);
3221
3222 l2cap_send_cmd(conn, conn->info_ident,
3223 L2CAP_INFO_REQ, sizeof(req), &req);
3224 } else {
3225 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3226 conn->info_ident = 0;
3227
3228 l2cap_conn_start(conn);
3229 }
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003230 break;
3231
3232 case L2CAP_IT_FIXED_CHAN:
3233 conn->fixed_chan_mask = rsp->data[0];
Marcel Holtmann984947d2009-02-06 23:35:19 +01003234 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003235 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003236
3237 l2cap_conn_start(conn);
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003238 break;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003239 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003240
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 return 0;
3242}
3243
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003244static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3245 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3246 void *data)
3247{
3248 struct l2cap_create_chan_req *req = data;
3249 struct l2cap_create_chan_rsp rsp;
3250 u16 psm, scid;
3251
3252 if (cmd_len != sizeof(*req))
3253 return -EPROTO;
3254
3255 if (!enable_hs)
3256 return -EINVAL;
3257
3258 psm = le16_to_cpu(req->psm);
3259 scid = le16_to_cpu(req->scid);
3260
3261 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3262
3263 /* Placeholder: Always reject */
3264 rsp.dcid = 0;
3265 rsp.scid = cpu_to_le16(scid);
3266 rsp.result = L2CAP_CR_NO_MEM;
3267 rsp.status = L2CAP_CS_NO_INFO;
3268
3269 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3270 sizeof(rsp), &rsp);
3271
3272 return 0;
3273}
3274
3275static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3276 struct l2cap_cmd_hdr *cmd, void *data)
3277{
3278 BT_DBG("conn %p", conn);
3279
3280 return l2cap_connect_rsp(conn, cmd, data);
3281}
3282
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003283static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3284 u16 icid, u16 result)
3285{
3286 struct l2cap_move_chan_rsp rsp;
3287
3288 BT_DBG("icid %d, result %d", icid, result);
3289
3290 rsp.icid = cpu_to_le16(icid);
3291 rsp.result = cpu_to_le16(result);
3292
3293 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3294}
3295
3296static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3297 struct l2cap_chan *chan, u16 icid, u16 result)
3298{
3299 struct l2cap_move_chan_cfm cfm;
3300 u8 ident;
3301
3302 BT_DBG("icid %d, result %d", icid, result);
3303
3304 ident = l2cap_get_ident(conn);
3305 if (chan)
3306 chan->ident = ident;
3307
3308 cfm.icid = cpu_to_le16(icid);
3309 cfm.result = cpu_to_le16(result);
3310
3311 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3312}
3313
3314static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3315 u16 icid)
3316{
3317 struct l2cap_move_chan_cfm_rsp rsp;
3318
3319 BT_DBG("icid %d", icid);
3320
3321 rsp.icid = cpu_to_le16(icid);
3322 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3323}
3324
3325static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3326 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3327{
3328 struct l2cap_move_chan_req *req = data;
3329 u16 icid = 0;
3330 u16 result = L2CAP_MR_NOT_ALLOWED;
3331
3332 if (cmd_len != sizeof(*req))
3333 return -EPROTO;
3334
3335 icid = le16_to_cpu(req->icid);
3336
3337 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3338
3339 if (!enable_hs)
3340 return -EINVAL;
3341
3342 /* Placeholder: Always refuse */
3343 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3344
3345 return 0;
3346}
3347
3348static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3349 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3350{
3351 struct l2cap_move_chan_rsp *rsp = data;
3352 u16 icid, result;
3353
3354 if (cmd_len != sizeof(*rsp))
3355 return -EPROTO;
3356
3357 icid = le16_to_cpu(rsp->icid);
3358 result = le16_to_cpu(rsp->result);
3359
3360 BT_DBG("icid %d, result %d", icid, result);
3361
3362 /* Placeholder: Always unconfirmed */
3363 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3364
3365 return 0;
3366}
3367
3368static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3369 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3370{
3371 struct l2cap_move_chan_cfm *cfm = data;
3372 u16 icid, result;
3373
3374 if (cmd_len != sizeof(*cfm))
3375 return -EPROTO;
3376
3377 icid = le16_to_cpu(cfm->icid);
3378 result = le16_to_cpu(cfm->result);
3379
3380 BT_DBG("icid %d, result %d", icid, result);
3381
3382 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3383
3384 return 0;
3385}
3386
3387static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3388 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3389{
3390 struct l2cap_move_chan_cfm_rsp *rsp = data;
3391 u16 icid;
3392
3393 if (cmd_len != sizeof(*rsp))
3394 return -EPROTO;
3395
3396 icid = le16_to_cpu(rsp->icid);
3397
3398 BT_DBG("icid %d", icid);
3399
3400 return 0;
3401}
3402
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003403static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003404 u16 to_multiplier)
3405{
3406 u16 max_latency;
3407
3408 if (min > max || min < 6 || max > 3200)
3409 return -EINVAL;
3410
3411 if (to_multiplier < 10 || to_multiplier > 3200)
3412 return -EINVAL;
3413
3414 if (max >= to_multiplier * 8)
3415 return -EINVAL;
3416
3417 max_latency = (to_multiplier * 8 / max) - 1;
3418 if (latency > 499 || latency > max_latency)
3419 return -EINVAL;
3420
3421 return 0;
3422}
3423
3424static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3425 struct l2cap_cmd_hdr *cmd, u8 *data)
3426{
3427 struct hci_conn *hcon = conn->hcon;
3428 struct l2cap_conn_param_update_req *req;
3429 struct l2cap_conn_param_update_rsp rsp;
3430 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003431 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003432
3433 if (!(hcon->link_mode & HCI_LM_MASTER))
3434 return -EINVAL;
3435
3436 cmd_len = __le16_to_cpu(cmd->len);
3437 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3438 return -EPROTO;
3439
3440 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003441 min = __le16_to_cpu(req->min);
3442 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003443 latency = __le16_to_cpu(req->latency);
3444 to_multiplier = __le16_to_cpu(req->to_multiplier);
3445
3446 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3447 min, max, latency, to_multiplier);
3448
3449 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003450
3451 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3452 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003453 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3454 else
3455 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3456
3457 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3458 sizeof(rsp), &rsp);
3459
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003460 if (!err)
3461 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3462
Claudio Takahaside731152011-02-11 19:28:55 -02003463 return 0;
3464}
3465
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003466static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3467 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3468{
3469 int err = 0;
3470
3471 switch (cmd->code) {
3472 case L2CAP_COMMAND_REJ:
3473 l2cap_command_rej(conn, cmd, data);
3474 break;
3475
3476 case L2CAP_CONN_REQ:
3477 err = l2cap_connect_req(conn, cmd, data);
3478 break;
3479
3480 case L2CAP_CONN_RSP:
3481 err = l2cap_connect_rsp(conn, cmd, data);
3482 break;
3483
3484 case L2CAP_CONF_REQ:
3485 err = l2cap_config_req(conn, cmd, cmd_len, data);
3486 break;
3487
3488 case L2CAP_CONF_RSP:
3489 err = l2cap_config_rsp(conn, cmd, data);
3490 break;
3491
3492 case L2CAP_DISCONN_REQ:
3493 err = l2cap_disconnect_req(conn, cmd, data);
3494 break;
3495
3496 case L2CAP_DISCONN_RSP:
3497 err = l2cap_disconnect_rsp(conn, cmd, data);
3498 break;
3499
3500 case L2CAP_ECHO_REQ:
3501 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3502 break;
3503
3504 case L2CAP_ECHO_RSP:
3505 break;
3506
3507 case L2CAP_INFO_REQ:
3508 err = l2cap_information_req(conn, cmd, data);
3509 break;
3510
3511 case L2CAP_INFO_RSP:
3512 err = l2cap_information_rsp(conn, cmd, data);
3513 break;
3514
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003515 case L2CAP_CREATE_CHAN_REQ:
3516 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3517 break;
3518
3519 case L2CAP_CREATE_CHAN_RSP:
3520 err = l2cap_create_channel_rsp(conn, cmd, data);
3521 break;
3522
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003523 case L2CAP_MOVE_CHAN_REQ:
3524 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3525 break;
3526
3527 case L2CAP_MOVE_CHAN_RSP:
3528 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3529 break;
3530
3531 case L2CAP_MOVE_CHAN_CFM:
3532 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3533 break;
3534
3535 case L2CAP_MOVE_CHAN_CFM_RSP:
3536 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3537 break;
3538
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003539 default:
3540 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3541 err = -EINVAL;
3542 break;
3543 }
3544
3545 return err;
3546}
3547
3548static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3549 struct l2cap_cmd_hdr *cmd, u8 *data)
3550{
3551 switch (cmd->code) {
3552 case L2CAP_COMMAND_REJ:
3553 return 0;
3554
3555 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003556 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003557
3558 case L2CAP_CONN_PARAM_UPDATE_RSP:
3559 return 0;
3560
3561 default:
3562 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3563 return -EINVAL;
3564 }
3565}
3566
3567static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3568 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569{
3570 u8 *data = skb->data;
3571 int len = skb->len;
3572 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003573 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
3575 l2cap_raw_recv(conn, skb);
3576
3577 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003578 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3580 data += L2CAP_CMD_HDR_SIZE;
3581 len -= L2CAP_CMD_HDR_SIZE;
3582
Al Viro88219a02007-07-29 00:17:25 -07003583 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584
Al Viro88219a02007-07-29 00:17:25 -07003585 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 -07003586
Al Viro88219a02007-07-29 00:17:25 -07003587 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 BT_DBG("corrupted command");
3589 break;
3590 }
3591
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003592 if (conn->hcon->type == LE_LINK)
3593 err = l2cap_le_sig_cmd(conn, &cmd, data);
3594 else
3595 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003598 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003599
3600 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601
3602 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003603 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3605 }
3606
Al Viro88219a02007-07-29 00:17:25 -07003607 data += cmd_len;
3608 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 }
3610
3611 kfree_skb(skb);
3612}
3613
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003614static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003615{
3616 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003617 int hdr_size;
3618
3619 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3620 hdr_size = L2CAP_EXT_HDR_SIZE;
3621 else
3622 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003623
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003624 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003625 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003626 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3627 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3628
3629 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003630 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003631 }
3632 return 0;
3633}
3634
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003635static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003636{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003637 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003638
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003639 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003640
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003641 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003642
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003643 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003644 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003645 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003646 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003647 }
3648
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003649 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003650 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003651
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003652 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003653
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003654 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003655 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003656 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003657 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003658 }
3659}
3660
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003661static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003662{
3663 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003664 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003665
3666 bt_cb(skb)->tx_seq = tx_seq;
3667 bt_cb(skb)->sar = sar;
3668
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003669 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003670
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003671 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003672
Szymon Janc039d9572011-11-16 09:32:19 +01003673 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003674 if (bt_cb(next_skb)->tx_seq == tx_seq)
3675 return -EINVAL;
3676
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003677 next_tx_seq_offset = __seq_offset(chan,
3678 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003679
3680 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003681 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003682 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003683 }
3684
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003685 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003686 next_skb = NULL;
3687 else
3688 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3689 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003690
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003691 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003692
3693 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003694}
3695
Mat Martineau84084a32011-07-22 14:54:00 -07003696static void append_skb_frag(struct sk_buff *skb,
3697 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003698{
Mat Martineau84084a32011-07-22 14:54:00 -07003699 /* skb->len reflects data in skb as well as all fragments
3700 * skb->data_len reflects only data in fragments
3701 */
3702 if (!skb_has_frag_list(skb))
3703 skb_shinfo(skb)->frag_list = new_frag;
3704
3705 new_frag->next = NULL;
3706
3707 (*last_frag)->next = new_frag;
3708 *last_frag = new_frag;
3709
3710 skb->len += new_frag->len;
3711 skb->data_len += new_frag->len;
3712 skb->truesize += new_frag->truesize;
3713}
3714
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003715static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003716{
3717 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003718
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003719 switch (__get_ctrl_sar(chan, control)) {
3720 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003721 if (chan->sdu)
3722 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003723
Mat Martineau84084a32011-07-22 14:54:00 -07003724 err = chan->ops->recv(chan->data, skb);
3725 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003726
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003727 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003728 if (chan->sdu)
3729 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003730
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003731 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003732 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003733
Mat Martineau84084a32011-07-22 14:54:00 -07003734 if (chan->sdu_len > chan->imtu) {
3735 err = -EMSGSIZE;
3736 break;
3737 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003738
Mat Martineau84084a32011-07-22 14:54:00 -07003739 if (skb->len >= chan->sdu_len)
3740 break;
3741
3742 chan->sdu = skb;
3743 chan->sdu_last_frag = skb;
3744
3745 skb = NULL;
3746 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003747 break;
3748
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003749 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003750 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003751 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003752
Mat Martineau84084a32011-07-22 14:54:00 -07003753 append_skb_frag(chan->sdu, skb,
3754 &chan->sdu_last_frag);
3755 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003756
Mat Martineau84084a32011-07-22 14:54:00 -07003757 if (chan->sdu->len >= chan->sdu_len)
3758 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003759
Mat Martineau84084a32011-07-22 14:54:00 -07003760 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003761 break;
3762
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003763 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003764 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003765 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003766
Mat Martineau84084a32011-07-22 14:54:00 -07003767 append_skb_frag(chan->sdu, skb,
3768 &chan->sdu_last_frag);
3769 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003770
Mat Martineau84084a32011-07-22 14:54:00 -07003771 if (chan->sdu->len != chan->sdu_len)
3772 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003773
Mat Martineau84084a32011-07-22 14:54:00 -07003774 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003775
Mat Martineau84084a32011-07-22 14:54:00 -07003776 if (!err) {
3777 /* Reassembly complete */
3778 chan->sdu = NULL;
3779 chan->sdu_last_frag = NULL;
3780 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003781 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003782 break;
3783 }
3784
Mat Martineau84084a32011-07-22 14:54:00 -07003785 if (err) {
3786 kfree_skb(skb);
3787 kfree_skb(chan->sdu);
3788 chan->sdu = NULL;
3789 chan->sdu_last_frag = NULL;
3790 chan->sdu_len = 0;
3791 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003792
Mat Martineau84084a32011-07-22 14:54:00 -07003793 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003794}
3795
Mat Martineau26f880d2011-07-07 09:39:01 -07003796static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003797{
Mat Martineau26f880d2011-07-07 09:39:01 -07003798 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003799
Mat Martineau26f880d2011-07-07 09:39:01 -07003800 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3801
Szymon Janc77f918b2012-01-11 10:59:48 +01003802 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003803}
3804
3805static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3806{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003807 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003808
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003809 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003810 goto done;
3811
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003812 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003813 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003814 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003815 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003816 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003817
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003818 __clear_retrans_timer(chan);
3819 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003820
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003821 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003822
3823done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003824 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3825 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003826
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003827 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003828}
3829
Mat Martineaue3281402011-07-07 09:39:02 -07003830void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003831{
Mat Martineaue3281402011-07-07 09:39:02 -07003832 if (chan->mode == L2CAP_MODE_ERTM) {
3833 if (busy)
3834 l2cap_ertm_enter_local_busy(chan);
3835 else
3836 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003837 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003838}
3839
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003840static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003841{
3842 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003843 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003844
Mat Martineaue3281402011-07-07 09:39:02 -07003845 while ((skb = skb_peek(&chan->srej_q)) &&
3846 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3847 int err;
3848
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003849 if (bt_cb(skb)->tx_seq != tx_seq)
3850 break;
3851
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003852 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003853 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003854 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003855
3856 if (err < 0) {
3857 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3858 break;
3859 }
3860
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003861 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3862 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003863 }
3864}
3865
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003866static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003867{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003868 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003869 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003870
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003871 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003872 if (l->tx_seq == tx_seq) {
3873 list_del(&l->list);
3874 kfree(l);
3875 return;
3876 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003877 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003878 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003879 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003880 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003881 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003882 }
3883}
3884
Szymon Jancaef89f22011-11-16 09:32:18 +01003885static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003886{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003887 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003888 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003889
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003890 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003891 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003892 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003893 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003894
3895 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003896 if (!new)
3897 return -ENOMEM;
3898
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003899 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003900
3901 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3902
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003903 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003904 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003905
3906 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003907
3908 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003909}
3910
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003911static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003912{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003913 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003914 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003915 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003916 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003917 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003918 int err = 0;
3919
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003920 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003921 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003922
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003923 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003924 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003925 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003926 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003927 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003928 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003929 }
3930
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003931 chan->expected_ack_seq = req_seq;
3932 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003933
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003934 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003935
3936 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003937 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003938 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003939 goto drop;
3940 }
3941
Szymon Janc77f918b2012-01-11 10:59:48 +01003942 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3943 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3944 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003945 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003946 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003947
Mat Martineau02f1b642011-06-29 14:35:19 -07003948 if (tx_seq == chan->expected_tx_seq)
3949 goto expected;
3950
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003951 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003952 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003953
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003954 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003955 struct srej_list, list);
3956 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003957 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003958 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003959
3960 list_del(&first->list);
3961 kfree(first);
3962
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003963 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003964 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003965 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003966 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003967 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003968 }
3969 } else {
3970 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003971
3972 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003973 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003974 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003975
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003976 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003977 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003978 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003979 return 0;
3980 }
3981 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003982
3983 err = l2cap_send_srejframe(chan, tx_seq);
3984 if (err < 0) {
3985 l2cap_send_disconn_req(chan->conn, chan, -err);
3986 return err;
3987 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003988 }
3989 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003990 expected_tx_seq_offset = __seq_offset(chan,
3991 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003992
3993 /* duplicated tx_seq */
3994 if (tx_seq_offset < expected_tx_seq_offset)
3995 goto drop;
3996
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003997 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003998
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003999 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004000
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03004001 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004002 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004003
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004004 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004005 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004006
Szymon Janc0ef3ef02012-01-11 10:59:46 +01004007 /* Set P-bit only if there are some I-frames to ack. */
4008 if (__clear_ack_timer(chan))
4009 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03004010
Szymon Jancaef89f22011-11-16 09:32:18 +01004011 err = l2cap_send_srejframe(chan, tx_seq);
4012 if (err < 0) {
4013 l2cap_send_disconn_req(chan->conn, chan, -err);
4014 return err;
4015 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004016 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004017 return 0;
4018
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004019expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004020 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004021
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004022 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03004023 bt_cb(skb)->tx_seq = tx_seq;
4024 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004025 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004026 return 0;
4027 }
4028
Mat Martineau84084a32011-07-22 14:54:00 -07004029 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004030 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4031
Mat Martineaue3281402011-07-07 09:39:02 -07004032 if (err < 0) {
4033 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4034 return err;
4035 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03004036
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004037 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004038 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004039 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03004040 }
4041
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03004042
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004043 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
4044 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004045 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03004046 else
4047 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03004048
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004049 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03004050
4051drop:
4052 kfree_skb(skb);
4053 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004054}
4055
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004056static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004057{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004058 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004059 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004060
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004061 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004062 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004063
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004064 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004065 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4066 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4067 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004068 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004069 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004070
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004071 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004072 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004073 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004074 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004075 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004076
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004077 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004078 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004079
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004080 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004081 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004082
4083 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004084 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004085 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004086 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004087
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004088 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4089 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004090 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004091 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004092 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004093 }
4094}
4095
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004096static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004097{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004098 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004099
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004100 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004101
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004102 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004103
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004104 chan->expected_ack_seq = tx_seq;
4105 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004106
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004107 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004108 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004109 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004110 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004111 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004112
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004113 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4114 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004115 }
4116}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004117static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004118{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004119 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004120
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004121 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004122
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004123 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004124
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004125 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004126 chan->expected_ack_seq = tx_seq;
4127 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004128
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004129 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004130 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004131
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004132 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004133
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004134 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004135 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004136 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004137 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004138 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004139 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004140 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004141 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004142 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004143 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004144 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004145 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004146 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004147 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004148 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004149 }
4150 }
4151}
4152
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004153static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004154{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004155 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004156
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004157 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004158
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004159 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004160 chan->expected_ack_seq = tx_seq;
4161 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004162
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004163 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004164 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004165
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004166 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004167 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004168 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004169 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004170 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004171 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004172
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004173 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004174 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004175 } else {
4176 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4177 l2cap_send_sframe(chan, rx_control);
4178 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004179}
4180
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004181static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004182{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004183 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004184
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004185 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004186 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004187 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004188 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004189 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004190 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004191 }
4192
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004193 switch (__get_ctrl_super(chan, rx_control)) {
4194 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004195 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004196 break;
4197
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004198 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004199 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004200 break;
4201
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004202 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004203 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004204 break;
4205
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004206 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004207 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004208 break;
4209 }
4210
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004211 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004212 return 0;
4213}
4214
Szymon Janccad8f1d02012-01-23 10:06:05 +01004215static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004216{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004217 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004218 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004219 int len, next_tx_seq_offset, req_seq_offset;
4220
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004221 control = __get_control(chan, skb->data);
4222 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004223 len = skb->len;
4224
4225 /*
4226 * We can just drop the corrupted I-frame here.
4227 * Receiver will miss it and start proper recovery
4228 * procedures and ask retransmission.
4229 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004230 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004231 goto drop;
4232
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004233 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004234 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004235
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004236 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004237 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004238
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004239 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004240 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004241 goto drop;
4242 }
4243
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004244 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004245
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004246 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4247
4248 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4249 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004250
4251 /* check for invalid req-seq */
4252 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004253 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004254 goto drop;
4255 }
4256
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004257 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004258 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004259 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004260 goto drop;
4261 }
4262
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004263 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004264 } else {
4265 if (len != 0) {
4266 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004267 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004268 goto drop;
4269 }
4270
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004271 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004272 }
4273
4274 return 0;
4275
4276drop:
4277 kfree_skb(skb);
4278 return 0;
4279}
4280
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4282{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004283 struct l2cap_chan *chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004284 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004285 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004286 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004288 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004289 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 BT_DBG("unknown cid 0x%4.4x", cid);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004291 /* Drop packet and return */
Dan Carpenter33790132012-02-28 09:52:46 +03004292 kfree_skb(skb);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004293 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 }
4295
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004296 l2cap_chan_lock(chan);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004297
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004298 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004300 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 goto drop;
4302
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004303 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004304 case L2CAP_MODE_BASIC:
4305 /* If socket recv buffers overflows we drop data here
4306 * which is *bad* because L2CAP has to be reliable.
4307 * But we don't have any other choice. L2CAP doesn't
4308 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004310 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004311 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004313 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004314 goto done;
4315 break;
4316
4317 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004318 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004319
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004320 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004321
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004322 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004323 control = __get_control(chan, skb->data);
4324 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004325 len = skb->len;
4326
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004327 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004328 goto drop;
4329
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004330 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004331 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004332
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004333 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004334 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004335
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004336 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004337 goto drop;
4338
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004339 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004340
Mat Martineau84084a32011-07-22 14:54:00 -07004341 if (chan->expected_tx_seq != tx_seq) {
4342 /* Frame(s) missing - must discard partial SDU */
4343 kfree_skb(chan->sdu);
4344 chan->sdu = NULL;
4345 chan->sdu_last_frag = NULL;
4346 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004347
Mat Martineau84084a32011-07-22 14:54:00 -07004348 /* TODO: Notify userland of missing data */
4349 }
4350
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004351 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004352
4353 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4354 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004355
4356 goto done;
4357
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004358 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004359 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004360 break;
4361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362
4363drop:
4364 kfree_skb(skb);
4365
4366done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004367 l2cap_chan_unlock(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +02004368
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 return 0;
4370}
4371
Al Viro8e036fc2007-07-29 00:16:36 -07004372static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004374 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004376 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4377 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 goto drop;
4379
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004380 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004382 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 goto drop;
4384
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004385 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 goto drop;
4387
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004388 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004389 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390
4391drop:
4392 kfree_skb(skb);
4393
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 return 0;
4395}
4396
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004397static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4398{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004399 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004400
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004401 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4402 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004403 goto drop;
4404
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004405 BT_DBG("chan %p, len %d", chan, skb->len);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004406
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004407 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004408 goto drop;
4409
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004410 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004411 goto drop;
4412
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004413 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004414 return 0;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004415
4416drop:
4417 kfree_skb(skb);
4418
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004419 return 0;
4420}
4421
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4423{
4424 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004425 u16 cid, len;
4426 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427
4428 skb_pull(skb, L2CAP_HDR_SIZE);
4429 cid = __le16_to_cpu(lh->cid);
4430 len = __le16_to_cpu(lh->len);
4431
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004432 if (len != skb->len) {
4433 kfree_skb(skb);
4434 return;
4435 }
4436
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4438
4439 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004440 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004441 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 l2cap_sig_channel(conn, skb);
4443 break;
4444
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004445 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004446 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 skb_pull(skb, 2);
4448 l2cap_conless_channel(conn, psm, skb);
4449 break;
4450
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004451 case L2CAP_CID_LE_DATA:
4452 l2cap_att_channel(conn, cid, skb);
4453 break;
4454
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004455 case L2CAP_CID_SMP:
4456 if (smp_sig_channel(conn, skb))
4457 l2cap_conn_del(conn->hcon, EACCES);
4458 break;
4459
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 default:
4461 l2cap_data_channel(conn, cid, skb);
4462 break;
4463 }
4464}
4465
4466/* ---- L2CAP interface with lower layer (HCI) ---- */
4467
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004468int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469{
4470 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004471 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4474
4475 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004476 read_lock(&chan_list_lock);
4477 list_for_each_entry(c, &chan_list, global_l) {
4478 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004479
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004480 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 continue;
4482
4483 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004484 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004485 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004486 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004488 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4489 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004490 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004491 lm2 |= HCI_LM_MASTER;
4492 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004494 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
4496 return exact ? lm1 : lm2;
4497}
4498
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004499int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500{
Marcel Holtmann01394182006-07-03 10:02:46 +02004501 struct l2cap_conn *conn;
4502
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4504
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 conn = l2cap_conn_add(hcon, status);
4507 if (conn)
4508 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004509 } else
Joe Perchese1750722011-06-29 18:18:29 -07004510 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511
4512 return 0;
4513}
4514
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004515int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004516{
4517 struct l2cap_conn *conn = hcon->l2cap_data;
4518
4519 BT_DBG("hcon %p", hcon);
4520
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004521 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004522 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004523 return conn->disc_reason;
4524}
4525
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004526int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527{
4528 BT_DBG("hcon %p reason %d", hcon, reason);
4529
Joe Perchese1750722011-06-29 18:18:29 -07004530 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 return 0;
4532}
4533
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004534static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004535{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004536 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004537 return;
4538
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004539 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004540 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004541 __clear_chan_timer(chan);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004542 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004543 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004544 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004545 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004546 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004547 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004548 }
4549}
4550
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004551int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004553 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004554 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555
Marcel Holtmann01394182006-07-03 10:02:46 +02004556 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004558
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 BT_DBG("conn %p", conn);
4560
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004561 if (hcon->type == LE_LINK) {
4562 smp_distribute_keys(conn, 0);
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02004563 cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004564 }
4565
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004566 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004568 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004569 l2cap_chan_lock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004571 BT_DBG("chan->scid %d", chan->scid);
4572
4573 if (chan->scid == L2CAP_CID_LE_DATA) {
4574 if (!status && encrypt) {
4575 chan->sec_level = hcon->sec_level;
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02004576 l2cap_chan_ready(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004577 }
4578
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004579 l2cap_chan_unlock(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004580 continue;
4581 }
4582
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004583 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004584 l2cap_chan_unlock(chan);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004585 continue;
4586 }
4587
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004588 if (!status && (chan->state == BT_CONNECTED ||
4589 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004590 l2cap_check_encryption(chan, encrypt);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004591 l2cap_chan_unlock(chan);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004592 continue;
4593 }
4594
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004595 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004596 if (!status) {
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +02004597 l2cap_send_conn_req(chan);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004598 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004599 __clear_chan_timer(chan);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004600 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004601 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004602 } else if (chan->state == BT_CONNECT2) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004603 struct sock *sk = chan->sk;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004604 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004605 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004606
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004607 lock_sock(sk);
4608
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004609 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004610 if (bt_sk(sk)->defer_setup) {
4611 struct sock *parent = bt_sk(sk)->parent;
4612 res = L2CAP_CR_PEND;
4613 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004614 if (parent)
4615 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004616 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004617 __l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004618 res = L2CAP_CR_SUCCESS;
4619 stat = L2CAP_CS_NO_INFO;
4620 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004621 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004622 __l2cap_state_change(chan, BT_DISCONN);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004623 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004624 res = L2CAP_CR_SEC_BLOCK;
4625 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004626 }
4627
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004628 release_sock(sk);
4629
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004630 rsp.scid = cpu_to_le16(chan->dcid);
4631 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004632 rsp.result = cpu_to_le16(res);
4633 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004634 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4635 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 }
4637
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004638 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639 }
4640
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004641 mutex_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004642
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 return 0;
4644}
4645
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004646int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647{
4648 struct l2cap_conn *conn = hcon->l2cap_data;
4649
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004650 if (!conn)
4651 conn = l2cap_conn_add(hcon, 0);
4652
4653 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 goto drop;
4655
4656 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4657
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004658 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004660 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004661 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 int len;
4663
4664 if (conn->rx_len) {
4665 BT_ERR("Unexpected start frame (len %d)", skb->len);
4666 kfree_skb(conn->rx_skb);
4667 conn->rx_skb = NULL;
4668 conn->rx_len = 0;
4669 l2cap_conn_unreliable(conn, ECOMM);
4670 }
4671
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004672 /* Start fragment always begin with Basic L2CAP header */
4673 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 BT_ERR("Frame is too short (len %d)", skb->len);
4675 l2cap_conn_unreliable(conn, ECOMM);
4676 goto drop;
4677 }
4678
4679 hdr = (struct l2cap_hdr *) skb->data;
4680 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004681 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682
4683 if (len == skb->len) {
4684 /* Complete frame received */
4685 l2cap_recv_frame(conn, skb);
4686 return 0;
4687 }
4688
4689 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4690
4691 if (skb->len > len) {
4692 BT_ERR("Frame is too long (len %d, expected len %d)",
4693 skb->len, len);
4694 l2cap_conn_unreliable(conn, ECOMM);
4695 goto drop;
4696 }
4697
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004698 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004699
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004700 if (chan && chan->sk) {
4701 struct sock *sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004702 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004703
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004704 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004705 BT_ERR("Frame exceeding recv MTU (len %d, "
4706 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004707 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004708 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004709 l2cap_conn_unreliable(conn, ECOMM);
4710 goto drop;
4711 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004712 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004713 }
4714
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004716 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4717 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 goto drop;
4719
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004720 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004721 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 conn->rx_len = len - skb->len;
4723 } else {
4724 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4725
4726 if (!conn->rx_len) {
4727 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4728 l2cap_conn_unreliable(conn, ECOMM);
4729 goto drop;
4730 }
4731
4732 if (skb->len > conn->rx_len) {
4733 BT_ERR("Fragment is too long (len %d, expected %d)",
4734 skb->len, conn->rx_len);
4735 kfree_skb(conn->rx_skb);
4736 conn->rx_skb = NULL;
4737 conn->rx_len = 0;
4738 l2cap_conn_unreliable(conn, ECOMM);
4739 goto drop;
4740 }
4741
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004742 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004743 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 conn->rx_len -= skb->len;
4745
4746 if (!conn->rx_len) {
4747 /* Complete frame received */
4748 l2cap_recv_frame(conn, conn->rx_skb);
4749 conn->rx_skb = NULL;
4750 }
4751 }
4752
4753drop:
4754 kfree_skb(skb);
4755 return 0;
4756}
4757
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004758static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004760 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004762 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004764 list_for_each_entry(c, &chan_list, global_l) {
4765 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004767 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 +01004768 batostr(&bt_sk(sk)->src),
4769 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004770 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004771 c->scid, c->dcid, c->imtu, c->omtu,
4772 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004775 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004776
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004777 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778}
4779
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004780static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4781{
4782 return single_open(file, l2cap_debugfs_show, inode->i_private);
4783}
4784
4785static const struct file_operations l2cap_debugfs_fops = {
4786 .open = l2cap_debugfs_open,
4787 .read = seq_read,
4788 .llseek = seq_lseek,
4789 .release = single_release,
4790};
4791
4792static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004794int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795{
4796 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004797
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004798 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 if (err < 0)
4800 return err;
4801
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004802 if (bt_debugfs) {
4803 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4804 bt_debugfs, NULL, &l2cap_debugfs_fops);
4805 if (!l2cap_debugfs)
4806 BT_ERR("Failed to create L2CAP debug file");
4807 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810}
4811
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004812void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004814 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004815 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816}
4817
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004818module_param(disable_ertm, bool, 0644);
4819MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");