blob: 2eac6184a231fa51d98a6becea143568de41a16c [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/unaligned.h>
53
54#include <net/bluetooth/bluetooth.h>
55#include <net/bluetooth/hci_core.h>
56#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030057#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Rusty Russelleb939922011-12-19 14:08:01 +000059bool disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020060
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070061static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070062static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Johannes Bergb5ad8b72011-06-01 08:54:45 +020064static LIST_HEAD(chan_list);
65static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
68 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030069static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
70 void *data);
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -030071static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030072static void l2cap_send_disconn_req(struct l2cap_conn *conn,
73 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Marcel Holtmann01394182006-07-03 10:02:46 +020075/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030076
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030077static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020078{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020079 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030080
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020081 list_for_each_entry(c, &conn->chan_l, list) {
82 if (c->dcid == cid)
83 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020084 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020085 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020086}
87
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030088static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020089{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020090 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030091
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020092 list_for_each_entry(c, &conn->chan_l, list) {
93 if (c->scid == cid)
94 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020095 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020096 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020097}
98
99/* Find channel with given SCID.
100 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300101static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200102{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300103 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300104
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200105 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300106 c = __l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200107 mutex_unlock(&conn->chan_lock);
108
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300109 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200110}
111
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300112static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200113{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200114 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300115
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200116 list_for_each_entry(c, &conn->chan_l, list) {
117 if (c->ident == ident)
118 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200119 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200120 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200121}
122
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300123static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200124{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300125 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300126
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200127 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300128 c = __l2cap_get_chan_by_ident(conn, ident);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200129 mutex_unlock(&conn->chan_lock);
130
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300131 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200132}
133
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300134static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300135{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300136 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300137
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300138 list_for_each_entry(c, &chan_list, global_l) {
139 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100140 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300141 }
Szymon Janc250938c2011-11-16 09:32:22 +0100142 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300143}
144
145int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
146{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300147 int err;
148
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200149 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300150
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300151 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300152 err = -EADDRINUSE;
153 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300154 }
155
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300156 if (psm) {
157 chan->psm = psm;
158 chan->sport = psm;
159 err = 0;
160 } else {
161 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300162
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300163 err = -EINVAL;
164 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300165 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300166 chan->psm = cpu_to_le16(p);
167 chan->sport = cpu_to_le16(p);
168 err = 0;
169 break;
170 }
171 }
172
173done:
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200174 write_unlock(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300175 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300176}
177
178int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
179{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200180 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300181
182 chan->scid = scid;
183
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200184 write_unlock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300185
186 return 0;
187}
188
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300189static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200190{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300191 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200192
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300193 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300194 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200195 return cid;
196 }
197
198 return 0;
199}
200
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200201static void __l2cap_state_change(struct l2cap_chan *chan, int state)
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300202{
Andrei Emeltchenko42d2d872012-02-17 11:40:57 +0200203 BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200204 state_to_string(state));
205
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300206 chan->state = state;
207 chan->ops->state_change(chan->data, state);
208}
209
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200210static void l2cap_state_change(struct l2cap_chan *chan, int state)
211{
212 struct sock *sk = chan->sk;
213
214 lock_sock(sk);
215 __l2cap_state_change(chan, state);
216 release_sock(sk);
217}
218
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200219static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
220{
221 struct sock *sk = chan->sk;
222
223 sk->sk_err = err;
224}
225
226static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
227{
228 struct sock *sk = chan->sk;
229
230 lock_sock(sk);
231 __l2cap_chan_set_err(chan, err);
232 release_sock(sk);
233}
234
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300235static void l2cap_chan_timeout(struct work_struct *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300236{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300237 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
238 chan_timer.work);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200239 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300240 int reason;
241
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200242 BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300243
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200244 mutex_lock(&conn->chan_lock);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200245 l2cap_chan_lock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300246
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300247 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300248 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300249 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300250 chan->sec_level != BT_SECURITY_SDP)
251 reason = ECONNREFUSED;
252 else
253 reason = ETIMEDOUT;
254
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300255 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300256
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200257 l2cap_chan_unlock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300258
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300259 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200260 mutex_unlock(&conn->chan_lock);
261
Ulisses Furquim371fd832011-12-21 20:02:36 -0200262 l2cap_chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300263}
264
Gustavo Padovaneef1d9b2012-03-25 13:59:16 -0300265struct l2cap_chan *l2cap_chan_create(void)
Marcel Holtmann01394182006-07-03 10:02:46 +0200266{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300267 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200268
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300269 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
270 if (!chan)
271 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200272
Andrei Emeltchenkoc03b3552012-02-21 12:54:56 +0200273 mutex_init(&chan->lock);
274
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200275 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300276 list_add(&chan->global_l, &chan_list);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200277 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300278
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300279 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300280
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300281 chan->state = BT_OPEN;
282
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300283 atomic_set(&chan->refcnt, 1);
284
Gustavo Padovaneef1d9b2012-03-25 13:59:16 -0300285 BT_DBG("chan %p", chan);
Szymon Jancabc545b2011-11-03 16:05:44 +0100286
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300287 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200288}
289
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300290void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300291{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200292 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300293 list_del(&chan->global_l);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200294 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300295
Ulisses Furquim371fd832011-12-21 20:02:36 -0200296 l2cap_chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300297}
298
Andrei Emeltchenkobd4b1652012-03-28 16:31:25 +0300299void l2cap_chan_set_defaults(struct l2cap_chan *chan)
300{
301 chan->fcs = L2CAP_FCS_CRC16;
302 chan->max_tx = L2CAP_DEFAULT_MAX_TX;
303 chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
304 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
305 chan->sec_level = BT_SECURITY_LOW;
306
307 set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
308}
309
Andrei Emeltchenko14a28492012-03-23 16:31:49 +0200310static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200311{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300312 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Andrei Emeltchenko097db762012-03-09 14:16:17 +0200313 __le16_to_cpu(chan->psm), chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200314
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200315 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100316
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300317 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200318
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200319 switch (chan->chan_type) {
320 case L2CAP_CHAN_CONN_ORIENTED:
Ville Tervob62f3282011-02-10 22:38:50 -0300321 if (conn->hcon->type == LE_LINK) {
322 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300323 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300324 chan->scid = L2CAP_CID_LE_DATA;
325 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300326 } else {
327 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300328 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300329 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300330 }
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200331 break;
332
333 case L2CAP_CHAN_CONN_LESS:
Marcel Holtmann01394182006-07-03 10:02:46 +0200334 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300335 chan->scid = L2CAP_CID_CONN_LESS;
336 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300337 chan->omtu = L2CAP_DEFAULT_MTU;
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200338 break;
339
340 default:
Marcel Holtmann01394182006-07-03 10:02:46 +0200341 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300342 chan->scid = L2CAP_CID_SIGNALING;
343 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300344 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200345 }
346
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300347 chan->local_id = L2CAP_BESTEFFORT_ID;
348 chan->local_stype = L2CAP_SERV_BESTEFFORT;
349 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
350 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
351 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
352 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
353
Ulisses Furquim371fd832011-12-21 20:02:36 -0200354 l2cap_chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300355
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200356 list_add(&chan->list, &conn->chan_l);
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200357}
358
Andrei Emeltchenko14a28492012-03-23 16:31:49 +0200359static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200360{
361 mutex_lock(&conn->chan_lock);
362 __l2cap_chan_add(conn, chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200363 mutex_unlock(&conn->chan_lock);
Marcel Holtmann01394182006-07-03 10:02:46 +0200364}
365
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300366static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200367{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300368 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300369 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200370 struct sock *parent = bt_sk(sk)->parent;
371
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300372 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200373
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300374 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200375
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900376 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300377 /* Delete from channel list */
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200378 list_del(&chan->list);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200379
Ulisses Furquim371fd832011-12-21 20:02:36 -0200380 l2cap_chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300381
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300382 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200383 hci_conn_put(conn->hcon);
384 }
385
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200386 lock_sock(sk);
387
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200388 __l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200389 sock_set_flag(sk, SOCK_ZAPPED);
390
391 if (err)
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200392 __l2cap_chan_set_err(chan, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200393
394 if (parent) {
395 bt_accept_unlink(sk);
396 parent->sk_data_ready(parent, 0);
397 } else
398 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300399
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200400 release_sock(sk);
401
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300402 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
403 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300404 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300405
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300406 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300407
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300408 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300409 struct srej_list *l, *tmp;
410
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300411 __clear_retrans_timer(chan);
412 __clear_monitor_timer(chan);
413 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300414
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300415 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300416
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300417 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300418 list_del(&l->list);
419 kfree(l);
420 }
421 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200422}
423
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300424static void l2cap_chan_cleanup_listen(struct sock *parent)
425{
426 struct sock *sk;
427
428 BT_DBG("parent %p", parent);
429
430 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300431 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300432 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200433
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200434 l2cap_chan_lock(chan);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300435 __clear_chan_timer(chan);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300436 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200437 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200438
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300439 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300440 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300441}
442
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300443void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300444{
445 struct l2cap_conn *conn = chan->conn;
446 struct sock *sk = chan->sk;
447
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200448 BT_DBG("chan %p state %s sk %p", chan,
449 state_to_string(chan->state), sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300450
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300451 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300452 case BT_LISTEN:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200453 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300454 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300455
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200456 __l2cap_state_change(chan, BT_CLOSED);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300457 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200458 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300459 break;
460
461 case BT_CONNECTED:
462 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300463 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300464 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300465 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300466 l2cap_send_disconn_req(conn, chan, reason);
467 } else
468 l2cap_chan_del(chan, reason);
469 break;
470
471 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300472 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300473 conn->hcon->type == ACL_LINK) {
474 struct l2cap_conn_rsp rsp;
475 __u16 result;
476
477 if (bt_sk(sk)->defer_setup)
478 result = L2CAP_CR_SEC_BLOCK;
479 else
480 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300481 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300482
483 rsp.scid = cpu_to_le16(chan->dcid);
484 rsp.dcid = cpu_to_le16(chan->scid);
485 rsp.result = cpu_to_le16(result);
486 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
487 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
488 sizeof(rsp), &rsp);
489 }
490
491 l2cap_chan_del(chan, reason);
492 break;
493
494 case BT_CONNECT:
495 case BT_DISCONN:
496 l2cap_chan_del(chan, reason);
497 break;
498
499 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200500 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300501 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200502 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300503 break;
504 }
505}
506
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300507static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530508{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300509 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300510 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530511 case BT_SECURITY_HIGH:
512 return HCI_AT_DEDICATED_BONDING_MITM;
513 case BT_SECURITY_MEDIUM:
514 return HCI_AT_DEDICATED_BONDING;
515 default:
516 return HCI_AT_NO_BONDING;
517 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300518 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300519 if (chan->sec_level == BT_SECURITY_LOW)
520 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530521
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300522 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530523 return HCI_AT_NO_BONDING_MITM;
524 else
525 return HCI_AT_NO_BONDING;
526 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300527 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530528 case BT_SECURITY_HIGH:
529 return HCI_AT_GENERAL_BONDING_MITM;
530 case BT_SECURITY_MEDIUM:
531 return HCI_AT_GENERAL_BONDING;
532 default:
533 return HCI_AT_NO_BONDING;
534 }
535 }
536}
537
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200538/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200539int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200540{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300541 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100542 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200543
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300544 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100545
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300546 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200547}
548
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200549static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200550{
551 u8 id;
552
553 /* Get next available identificator.
554 * 1 - 128 are used by kernel.
555 * 129 - 199 are reserved.
556 * 200 - 254 are used by utilities like l2ping, etc.
557 */
558
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200559 spin_lock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200560
561 if (++conn->tx_ident > 128)
562 conn->tx_ident = 1;
563
564 id = conn->tx_ident;
565
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200566 spin_unlock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200567
568 return id;
569}
570
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300571static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200572{
573 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200574 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200575
576 BT_DBG("code 0x%2.2x", code);
577
578 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300579 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200580
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200581 if (lmp_no_flush_capable(conn->hcon->hdev))
582 flags = ACL_START_NO_FLUSH;
583 else
584 flags = ACL_START;
585
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700586 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200587 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700588
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200589 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200590}
591
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200592static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
593{
594 struct hci_conn *hcon = chan->conn->hcon;
595 u16 flags;
596
597 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
598 skb->priority);
599
600 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
601 lmp_no_flush_capable(hcon->hdev))
602 flags = ACL_START_NO_FLUSH;
603 else
604 flags = ACL_START;
605
606 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
607 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608}
609
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300610static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300611{
612 struct sk_buff *skb;
613 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300614 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300615 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300616
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300617 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300618 return;
619
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300620 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
621 hlen = L2CAP_EXT_HDR_SIZE;
622 else
623 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300624
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300625 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300626 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300627
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300628 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300629
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300630 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300631
632 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300633
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300634 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300635 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300636
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300637 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300638 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300639
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300640 skb = bt_skb_alloc(count, GFP_ATOMIC);
641 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300642 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300643
644 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300645 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300646 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300647
648 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300649
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300650 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300651 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
652 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300653 }
654
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200655 skb->priority = HCI_PRIO_MAX;
656 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300657}
658
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300659static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300660{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300661 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300662 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300663 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300664 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300665 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300666
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300667 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300668
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300669 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300670}
671
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300672static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300673{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300674 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300675}
676
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200677static void l2cap_send_conn_req(struct l2cap_chan *chan)
678{
679 struct l2cap_conn *conn = chan->conn;
680 struct l2cap_conn_req req;
681
682 req.scid = cpu_to_le16(chan->scid);
683 req.psm = chan->psm;
684
685 chan->ident = l2cap_get_ident(conn);
686
687 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
688
689 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
690}
691
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300692static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200693{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300694 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200695
696 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100697 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
698 return;
699
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200700 if (l2cap_chan_check_security(chan) &&
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200701 __l2cap_no_conn_pending(chan))
702 l2cap_send_conn_req(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200703 } else {
704 struct l2cap_info_req req;
705 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
706
707 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
708 conn->info_ident = l2cap_get_ident(conn);
709
Marcel Holtmannba13ccd2012-03-01 14:25:33 -0800710 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200711
712 l2cap_send_cmd(conn, conn->info_ident,
713 L2CAP_INFO_REQ, sizeof(req), &req);
714 }
715}
716
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300717static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
718{
719 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300720 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300721 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
722
723 switch (mode) {
724 case L2CAP_MODE_ERTM:
725 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
726 case L2CAP_MODE_STREAMING:
727 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
728 default:
729 return 0x00;
730 }
731}
732
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300733static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300734{
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200735 struct sock *sk = chan->sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300736 struct l2cap_disconn_req req;
737
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300738 if (!conn)
739 return;
740
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300741 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300742 __clear_retrans_timer(chan);
743 __clear_monitor_timer(chan);
744 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300745 }
746
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300747 req.dcid = cpu_to_le16(chan->dcid);
748 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300749 l2cap_send_cmd(conn, l2cap_get_ident(conn),
750 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300751
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200752 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200753 __l2cap_state_change(chan, BT_DISCONN);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200754 __l2cap_chan_set_err(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200755 release_sock(sk);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300756}
757
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200759static void l2cap_conn_start(struct l2cap_conn *conn)
760{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200761 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200762
763 BT_DBG("conn %p", conn);
764
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200765 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200766
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200767 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300768 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300769
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200770 l2cap_chan_lock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200771
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300772 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200773 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200774 continue;
775 }
776
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300777 if (chan->state == BT_CONNECT) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200778 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300779 !__l2cap_no_conn_pending(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200780 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300781 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200782 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300783
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300784 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
785 && test_bit(CONF_STATE2_DEVICE,
786 &chan->conf_state)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300787 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200788 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300789 continue;
790 }
791
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200792 l2cap_send_conn_req(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300793
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300794 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200795 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300796 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300797 rsp.scid = cpu_to_le16(chan->dcid);
798 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200799
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200800 if (l2cap_chan_check_security(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200801 lock_sock(sk);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100802 if (bt_sk(sk)->defer_setup) {
803 struct sock *parent = bt_sk(sk)->parent;
804 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
805 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000806 if (parent)
807 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100808
809 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200810 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100811 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
812 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
813 }
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200814 release_sock(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200815 } else {
816 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
817 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
818 }
819
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300820 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
821 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300822
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300823 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300824 rsp.result != L2CAP_CR_SUCCESS) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200825 l2cap_chan_unlock(chan);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300826 continue;
827 }
828
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300829 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300830 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300831 l2cap_build_conf_req(chan, buf), buf);
832 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200833 }
834
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200835 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200836 }
837
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200838 mutex_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200839}
840
Ville Tervob62f3282011-02-10 22:38:50 -0300841/* Find socket with cid and source bdaddr.
842 * Returns closest match, locked.
843 */
Andrei Emeltchenkod9b88702012-03-12 12:13:08 +0200844static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
845 bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300846{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300847 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300848
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300849 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300850
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300851 list_for_each_entry(c, &chan_list, global_l) {
852 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300853
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300854 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300855 continue;
856
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300857 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300858 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300859 if (!bacmp(&bt_sk(sk)->src, src)) {
860 read_unlock(&chan_list_lock);
861 return c;
862 }
Ville Tervob62f3282011-02-10 22:38:50 -0300863
864 /* Closest match */
865 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300866 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300867 }
868 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300869
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300870 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300871
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300872 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300873}
874
875static void l2cap_le_conn_ready(struct l2cap_conn *conn)
876{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300877 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300878 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300879
880 BT_DBG("");
881
882 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300883 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300884 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300885 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300886 return;
887
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300888 parent = pchan->sk;
889
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300890 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300891
Ville Tervob62f3282011-02-10 22:38:50 -0300892 /* Check for backlog size */
893 if (sk_acceptq_is_full(parent)) {
894 BT_DBG("backlog full %d", parent->sk_ack_backlog);
895 goto clean;
896 }
897
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300898 chan = pchan->ops->new_connection(pchan->data);
899 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300900 goto clean;
901
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300902 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300903
Ville Tervob62f3282011-02-10 22:38:50 -0300904 hci_conn_hold(conn->hcon);
905
Ville Tervob62f3282011-02-10 22:38:50 -0300906 bacpy(&bt_sk(sk)->src, conn->src);
907 bacpy(&bt_sk(sk)->dst, conn->dst);
908
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300909 bt_accept_enqueue(parent, sk);
910
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200911 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300912
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300913 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300914
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200915 __l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300916 parent->sk_data_ready(parent, 0);
917
Ville Tervob62f3282011-02-10 22:38:50 -0300918clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300919 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300920}
921
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200922static void l2cap_chan_ready(struct l2cap_chan *chan)
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300923{
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200924 struct sock *sk = chan->sk;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200925 struct sock *parent;
926
927 lock_sock(sk);
928
929 parent = bt_sk(sk)->parent;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300930
931 BT_DBG("sk %p, parent %p", sk, parent);
932
933 chan->conf_state = 0;
934 __clear_chan_timer(chan);
935
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200936 __l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300937 sk->sk_state_change(sk);
938
939 if (parent)
940 parent->sk_data_ready(parent, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200941
942 release_sock(sk);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300943}
944
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200945static void l2cap_conn_ready(struct l2cap_conn *conn)
946{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300947 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200948
949 BT_DBG("conn %p", conn);
950
Ville Tervob62f3282011-02-10 22:38:50 -0300951 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
952 l2cap_le_conn_ready(conn);
953
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300954 if (conn->hcon->out && conn->hcon->type == LE_LINK)
955 smp_conn_security(conn, conn->hcon->pending_sec_level);
956
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200957 mutex_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200958
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200959 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300960
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200961 l2cap_chan_lock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200962
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300963 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300964 if (smp_conn_security(conn, chan->sec_level))
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200965 l2cap_chan_ready(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300966
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300967 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200968 struct sock *sk = chan->sk;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300969 __clear_chan_timer(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200970 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200971 __l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200972 sk->sk_state_change(sk);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200973 release_sock(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300974
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300975 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300976 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200977
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200978 l2cap_chan_unlock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200979 }
980
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200981 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200982}
983
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200984/* Notify sockets that we cannot guaranty reliability anymore */
985static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
986{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300987 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200988
989 BT_DBG("conn %p", conn);
990
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200991 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200992
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200993 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300994 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200995 __l2cap_chan_set_err(chan, err);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200996 }
997
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200998 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200999}
1000
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -02001001static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001002{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -02001003 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001004 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001005
Marcel Holtmann984947d2009-02-06 23:35:19 +01001006 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01001007 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01001008
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001009 l2cap_conn_start(conn);
1010}
1011
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001012static void l2cap_conn_del(struct hci_conn *hcon, int err)
1013{
1014 struct l2cap_conn *conn = hcon->l2cap_data;
1015 struct l2cap_chan *chan, *l;
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001016
1017 if (!conn)
1018 return;
1019
1020 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1021
1022 kfree_skb(conn->rx_skb);
1023
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001024 mutex_lock(&conn->chan_lock);
1025
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001026 /* Kill channels */
1027 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001028 l2cap_chan_lock(chan);
1029
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001030 l2cap_chan_del(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001031
1032 l2cap_chan_unlock(chan);
1033
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001034 chan->ops->close(chan->data);
1035 }
1036
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001037 mutex_unlock(&conn->chan_lock);
1038
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001039 hci_chan_del(conn->hchan);
1040
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001041 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim127074b2012-01-30 18:26:29 -02001042 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001043
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001044 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim127074b2012-01-30 18:26:29 -02001045 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001046 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001047 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001048
1049 hcon->l2cap_data = NULL;
1050 kfree(conn);
1051}
1052
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001053static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001054{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001055 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1056 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001057
1058 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1059}
1060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1062{
Marcel Holtmann01394182006-07-03 10:02:46 +02001063 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001064 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Marcel Holtmann01394182006-07-03 10:02:46 +02001066 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 return conn;
1068
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001069 hchan = hci_chan_create(hcon);
1070 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001073 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1074 if (!conn) {
1075 hci_chan_del(hchan);
1076 return NULL;
1077 }
1078
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 hcon->l2cap_data = conn;
1080 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001081 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001083 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001084
Ville Tervoacd7d372011-02-10 22:38:49 -03001085 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1086 conn->mtu = hcon->hdev->le_mtu;
1087 else
1088 conn->mtu = hcon->hdev->acl_mtu;
1089
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 conn->src = &hcon->hdev->bdaddr;
1091 conn->dst = &hcon->dst;
1092
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001093 conn->feat_mask = 0;
1094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 spin_lock_init(&conn->lock);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001096 mutex_init(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001097
1098 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001100 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001101 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001102 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001103 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001104
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001105 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 return conn;
1108}
1109
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112/* Find socket with psm and source bdaddr.
1113 * Returns closest match.
1114 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001115static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001117 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001119 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001120
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001121 list_for_each_entry(c, &chan_list, global_l) {
1122 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001123
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001124 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 continue;
1126
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001127 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001129 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001130 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001131 return c;
1132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
1134 /* Closest match */
1135 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001136 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 }
1138 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001140 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001141
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001142 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143}
1144
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001145int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001147 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 struct l2cap_conn *conn;
1150 struct hci_conn *hcon;
1151 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001152 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001153 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001155 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Andrei Emeltchenko097db762012-03-09 14:16:17 +02001156 __le16_to_cpu(chan->psm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001158 hdev = hci_get_route(dst, src);
1159 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 return -EHOSTUNREACH;
1161
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001162 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001164 l2cap_chan_lock(chan);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001165
1166 /* PSM must be odd and lsb of upper byte must be 0 */
1167 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1168 chan->chan_type != L2CAP_CHAN_RAW) {
1169 err = -EINVAL;
1170 goto done;
1171 }
1172
1173 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1174 err = -EINVAL;
1175 goto done;
1176 }
1177
1178 switch (chan->mode) {
1179 case L2CAP_MODE_BASIC:
1180 break;
1181 case L2CAP_MODE_ERTM:
1182 case L2CAP_MODE_STREAMING:
1183 if (!disable_ertm)
1184 break;
1185 /* fall through */
1186 default:
1187 err = -ENOTSUPP;
1188 goto done;
1189 }
1190
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001191 lock_sock(sk);
1192
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001193 switch (sk->sk_state) {
1194 case BT_CONNECT:
1195 case BT_CONNECT2:
1196 case BT_CONFIG:
1197 /* Already connecting */
1198 err = 0;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001199 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001200 goto done;
1201
1202 case BT_CONNECTED:
1203 /* Already connected */
1204 err = -EISCONN;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001205 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001206 goto done;
1207
1208 case BT_OPEN:
1209 case BT_BOUND:
1210 /* Can connect */
1211 break;
1212
1213 default:
1214 err = -EBADFD;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001215 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001216 goto done;
1217 }
1218
1219 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001220 bacpy(&bt_sk(sk)->dst, dst);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001221
1222 release_sock(sk);
1223
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001224 chan->psm = psm;
1225 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001227 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001228
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001229 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001230 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001231 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001232 else
1233 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001234 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001235
Ville Tervo30e76272011-02-22 16:10:53 -03001236 if (IS_ERR(hcon)) {
1237 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240
1241 conn = l2cap_conn_add(hcon, 0);
1242 if (!conn) {
1243 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001244 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 goto done;
1246 }
1247
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 /* Update source addr of the socket */
1249 bacpy(src, conn->src);
1250
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001251 l2cap_chan_unlock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001252 l2cap_chan_add(conn, chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001253 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001254
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001255 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001256 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001259 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001260 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001261 if (l2cap_chan_check_security(chan))
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001262 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001263 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001264 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 }
1266
Ville Tervo30e76272011-02-22 16:10:53 -03001267 err = 0;
1268
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001270 l2cap_chan_unlock(chan);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001271 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 hci_dev_put(hdev);
1273 return err;
1274}
1275
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001276int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001277{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001278 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001279 DECLARE_WAITQUEUE(wait, current);
1280 int err = 0;
1281 int timeo = HZ/5;
1282
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001283 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001284 set_current_state(TASK_INTERRUPTIBLE);
1285 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001286 if (!timeo)
1287 timeo = HZ/5;
1288
1289 if (signal_pending(current)) {
1290 err = sock_intr_errno(timeo);
1291 break;
1292 }
1293
1294 release_sock(sk);
1295 timeo = schedule_timeout(timeo);
1296 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001297 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001298
1299 err = sock_error(sk);
1300 if (err)
1301 break;
1302 }
1303 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001304 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001305 return err;
1306}
1307
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001308static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001309{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001310 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1311 monitor_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001312
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001313 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001314
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001315 l2cap_chan_lock(chan);
1316
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001317 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001318 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001319 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001320 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001321 return;
1322 }
1323
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001324 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001325 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001326
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001327 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001328 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001329 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001330}
1331
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001332static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001333{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001334 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1335 retrans_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001336
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001337 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001338
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001339 l2cap_chan_lock(chan);
1340
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001341 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001342 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001343
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001344 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001345
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001346 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001347
1348 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001349 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001350}
1351
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001352static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001353{
1354 struct sk_buff *skb;
1355
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001356 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001357 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001358 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001359 break;
1360
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001361 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001362 kfree_skb(skb);
1363
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001364 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001365 }
1366
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001367 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001368 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001369}
1370
Szymon Janc67c9e842011-07-28 16:24:33 +02001371static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001372{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001373 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001374 u32 control;
1375 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001376
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001377 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001378 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001379 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001380 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001381
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001382 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001383 fcs = crc16(0, (u8 *)skb->data,
1384 skb->len - L2CAP_FCS_SIZE);
1385 put_unaligned_le16(fcs,
1386 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001387 }
1388
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001389 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001390
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001391 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001392 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001393}
1394
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001395static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001396{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001397 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001398 u16 fcs;
1399 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001400
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001401 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001402 if (!skb)
1403 return;
1404
Szymon Jancd1726b62011-11-16 09:32:20 +01001405 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001406 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001407 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001408
Szymon Jancd1726b62011-11-16 09:32:20 +01001409 skb = skb_queue_next(&chan->tx_q, skb);
1410 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001411
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001412 if (chan->remote_max_tx &&
1413 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001414 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001415 return;
1416 }
1417
1418 tx_skb = skb_clone(skb, GFP_ATOMIC);
1419 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001420
1421 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001422 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001423
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001424 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001425 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001426
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001427 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001428 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001429
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001430 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001431
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001432 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001433 fcs = crc16(0, (u8 *)tx_skb->data,
1434 tx_skb->len - L2CAP_FCS_SIZE);
1435 put_unaligned_le16(fcs,
1436 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001437 }
1438
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001439 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001440}
1441
Szymon Janc67c9e842011-07-28 16:24:33 +02001442static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001443{
1444 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001445 u16 fcs;
1446 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001447 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001448
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001449 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001450 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001451
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001452 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001453
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001454 if (chan->remote_max_tx &&
1455 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001456 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001457 break;
1458 }
1459
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001460 tx_skb = skb_clone(skb, GFP_ATOMIC);
1461
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001462 bt_cb(skb)->retries++;
1463
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001464 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001465 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001466
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001467 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001468 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001469
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001470 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001471 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001472
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001473 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001474
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001475 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001476 fcs = crc16(0, (u8 *)skb->data,
1477 tx_skb->len - L2CAP_FCS_SIZE);
1478 put_unaligned_le16(fcs, skb->data +
1479 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001480 }
1481
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001482 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001483
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001484 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001485
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001486 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001487
1488 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001489
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001490 if (bt_cb(skb)->retries == 1) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001491 chan->unacked_frames++;
Szymon Janc930fa4a2012-02-07 15:43:02 +01001492
1493 if (!nsent++)
1494 __clear_ack_timer(chan);
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001495 }
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301496
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001497 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001498
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001499 if (skb_queue_is_last(&chan->tx_q, skb))
1500 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001501 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001502 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001503 }
1504
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001505 return nsent;
1506}
1507
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001508static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001509{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001510 int ret;
1511
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001512 if (!skb_queue_empty(&chan->tx_q))
1513 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001514
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001515 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001516 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001517 return ret;
1518}
1519
Szymon Jancb17e73b2012-01-11 10:59:47 +01001520static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001521{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001522 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001523
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001524 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001525
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001526 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001527 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001528 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001529 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001530 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001531 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001532
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001533 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001534 return;
1535
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001536 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001537 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001538}
1539
Szymon Jancb17e73b2012-01-11 10:59:47 +01001540static void l2cap_send_ack(struct l2cap_chan *chan)
1541{
1542 __clear_ack_timer(chan);
1543 __l2cap_send_ack(chan);
1544}
1545
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001546static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001547{
1548 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001549 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001550
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001551 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001552 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001553
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001554 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001555 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001556
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001557 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001558}
1559
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001560static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
1561 struct msghdr *msg, int len,
1562 int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001563{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001564 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001565 struct sk_buff **frag;
1566 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001567
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001568 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001569 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570
1571 sent += count;
1572 len -= count;
1573
1574 /* Continuation fragments (no L2CAP header) */
1575 frag = &skb_shinfo(skb)->frag_list;
1576 while (len) {
1577 count = min_t(unsigned int, conn->mtu, len);
1578
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001579 *frag = chan->ops->alloc_skb(chan, count,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001580 msg->msg_flags & MSG_DONTWAIT,
1581 &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001582
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001584 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001585 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1586 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001588 (*frag)->priority = skb->priority;
1589
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 sent += count;
1591 len -= count;
1592
1593 frag = &(*frag)->next;
1594 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595
1596 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001597}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001599static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1600 struct msghdr *msg, size_t len,
1601 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001602{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001603 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001604 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001605 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001606 struct l2cap_hdr *lh;
1607
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001608 BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001609
1610 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001611
1612 skb = chan->ops->alloc_skb(chan, count + hlen,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001613 msg->msg_flags & MSG_DONTWAIT, &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001614
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001615 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001616 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001617
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001618 skb->priority = priority;
1619
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001620 /* Create L2CAP header */
1621 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001622 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001623 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko097db762012-03-09 14:16:17 +02001624 put_unaligned(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001625
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001626 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001627 if (unlikely(err < 0)) {
1628 kfree_skb(skb);
1629 return ERR_PTR(err);
1630 }
1631 return skb;
1632}
1633
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001634static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1635 struct msghdr *msg, size_t len,
1636 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001637{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001638 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001639 struct sk_buff *skb;
1640 int err, count, hlen = L2CAP_HDR_SIZE;
1641 struct l2cap_hdr *lh;
1642
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001643 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001644
1645 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001646
1647 skb = chan->ops->alloc_skb(chan, count + hlen,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001648 msg->msg_flags & MSG_DONTWAIT, &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001649
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001650 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001651 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001652
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001653 skb->priority = priority;
1654
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001655 /* Create L2CAP header */
1656 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001657 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001658 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1659
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001660 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001661 if (unlikely(err < 0)) {
1662 kfree_skb(skb);
1663 return ERR_PTR(err);
1664 }
1665 return skb;
1666}
1667
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001668static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1669 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001670 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001671{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001672 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001673 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001674 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001675 struct l2cap_hdr *lh;
1676
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001677 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001678
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001679 if (!conn)
1680 return ERR_PTR(-ENOTCONN);
1681
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001682 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1683 hlen = L2CAP_EXT_HDR_SIZE;
1684 else
1685 hlen = L2CAP_ENH_HDR_SIZE;
1686
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001687 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001688 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001689
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001690 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001691 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001692
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001693 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001694
1695 skb = chan->ops->alloc_skb(chan, count + hlen,
1696 msg->msg_flags & MSG_DONTWAIT, &err);
1697
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001698 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001699 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001700
1701 /* Create L2CAP header */
1702 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001703 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001704 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001705
1706 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1707
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001708 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001709 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001710
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001711 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001712 if (unlikely(err < 0)) {
1713 kfree_skb(skb);
1714 return ERR_PTR(err);
1715 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001716
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001717 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001718 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001719
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001720 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001721 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722}
1723
Szymon Janc67c9e842011-07-28 16:24:33 +02001724static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001725{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001726 struct sk_buff *skb;
1727 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001728 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001729 size_t size = 0;
1730
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001731 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001732 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001733 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001734 if (IS_ERR(skb))
1735 return PTR_ERR(skb);
1736
1737 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001738 len -= chan->remote_mps;
1739 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001740
1741 while (len > 0) {
1742 size_t buflen;
1743
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001744 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001745 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001746 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001747 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001748 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001749 buflen = len;
1750 }
1751
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001752 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001753 if (IS_ERR(skb)) {
1754 skb_queue_purge(&sar_queue);
1755 return PTR_ERR(skb);
1756 }
1757
1758 __skb_queue_tail(&sar_queue, skb);
1759 len -= buflen;
1760 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001761 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001762 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1763 if (chan->tx_send_head == NULL)
1764 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001765
1766 return size;
1767}
1768
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001769int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1770 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001771{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001772 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001773 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001774 int err;
1775
1776 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001777 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001778 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001779 if (IS_ERR(skb))
1780 return PTR_ERR(skb);
1781
1782 l2cap_do_send(chan, skb);
1783 return len;
1784 }
1785
1786 switch (chan->mode) {
1787 case L2CAP_MODE_BASIC:
1788 /* Check outgoing MTU */
1789 if (len > chan->omtu)
1790 return -EMSGSIZE;
1791
1792 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001793 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001794 if (IS_ERR(skb))
1795 return PTR_ERR(skb);
1796
1797 l2cap_do_send(chan, skb);
1798 err = len;
1799 break;
1800
1801 case L2CAP_MODE_ERTM:
1802 case L2CAP_MODE_STREAMING:
1803 /* Entire SDU fits into one PDU */
1804 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001805 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001806 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1807 0);
1808 if (IS_ERR(skb))
1809 return PTR_ERR(skb);
1810
1811 __skb_queue_tail(&chan->tx_q, skb);
1812
1813 if (chan->tx_send_head == NULL)
1814 chan->tx_send_head = skb;
1815
1816 } else {
1817 /* Segment SDU into multiples PDUs */
1818 err = l2cap_sar_segment_sdu(chan, msg, len);
1819 if (err < 0)
1820 return err;
1821 }
1822
1823 if (chan->mode == L2CAP_MODE_STREAMING) {
1824 l2cap_streaming_send(chan);
1825 err = len;
1826 break;
1827 }
1828
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001829 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1830 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001831 err = len;
1832 break;
1833 }
1834
1835 err = l2cap_ertm_send(chan);
1836 if (err >= 0)
1837 err = len;
1838
1839 break;
1840
1841 default:
1842 BT_DBG("bad state %1.1x", chan->mode);
1843 err = -EBADFD;
1844 }
1845
1846 return err;
1847}
1848
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849/* Copy frame to all raw sockets on that connection */
1850static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1851{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001853 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854
1855 BT_DBG("conn %p", conn);
1856
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001857 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001858
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001859 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001860 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001861 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 continue;
1863
1864 /* Don't send frame to the socket it came from */
1865 if (skb->sk == sk)
1866 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001867 nskb = skb_clone(skb, GFP_ATOMIC);
1868 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 continue;
1870
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001871 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872 kfree_skb(nskb);
1873 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001874
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001875 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876}
1877
1878/* ---- L2CAP signalling commands ---- */
1879static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1880 u8 code, u8 ident, u16 dlen, void *data)
1881{
1882 struct sk_buff *skb, **frag;
1883 struct l2cap_cmd_hdr *cmd;
1884 struct l2cap_hdr *lh;
1885 int len, count;
1886
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001887 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1888 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889
1890 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1891 count = min_t(unsigned int, conn->mtu, len);
1892
1893 skb = bt_skb_alloc(count, GFP_ATOMIC);
1894 if (!skb)
1895 return NULL;
1896
1897 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001898 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001899
1900 if (conn->hcon->type == LE_LINK)
1901 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1902 else
1903 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904
1905 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1906 cmd->code = code;
1907 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001908 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909
1910 if (dlen) {
1911 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1912 memcpy(skb_put(skb, count), data, count);
1913 data += count;
1914 }
1915
1916 len -= skb->len;
1917
1918 /* Continuation fragments (no L2CAP header) */
1919 frag = &skb_shinfo(skb)->frag_list;
1920 while (len) {
1921 count = min_t(unsigned int, conn->mtu, len);
1922
1923 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1924 if (!*frag)
1925 goto fail;
1926
1927 memcpy(skb_put(*frag, count), data, count);
1928
1929 len -= count;
1930 data += count;
1931
1932 frag = &(*frag)->next;
1933 }
1934
1935 return skb;
1936
1937fail:
1938 kfree_skb(skb);
1939 return NULL;
1940}
1941
1942static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1943{
1944 struct l2cap_conf_opt *opt = *ptr;
1945 int len;
1946
1947 len = L2CAP_CONF_OPT_SIZE + opt->len;
1948 *ptr += len;
1949
1950 *type = opt->type;
1951 *olen = opt->len;
1952
1953 switch (opt->len) {
1954 case 1:
1955 *val = *((u8 *) opt->val);
1956 break;
1957
1958 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001959 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 break;
1961
1962 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001963 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 break;
1965
1966 default:
1967 *val = (unsigned long) opt->val;
1968 break;
1969 }
1970
1971 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1972 return len;
1973}
1974
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1976{
1977 struct l2cap_conf_opt *opt = *ptr;
1978
1979 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1980
1981 opt->type = type;
1982 opt->len = len;
1983
1984 switch (len) {
1985 case 1:
1986 *((u8 *) opt->val) = val;
1987 break;
1988
1989 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001990 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 break;
1992
1993 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001994 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 break;
1996
1997 default:
1998 memcpy(opt->val, (void *) val, len);
1999 break;
2000 }
2001
2002 *ptr += L2CAP_CONF_OPT_SIZE + len;
2003}
2004
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002005static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
2006{
2007 struct l2cap_conf_efs efs;
2008
Szymon Janc1ec918c2011-11-16 09:32:21 +01002009 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002010 case L2CAP_MODE_ERTM:
2011 efs.id = chan->local_id;
2012 efs.stype = chan->local_stype;
2013 efs.msdu = cpu_to_le16(chan->local_msdu);
2014 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2015 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
2016 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
2017 break;
2018
2019 case L2CAP_MODE_STREAMING:
2020 efs.id = 1;
2021 efs.stype = L2CAP_SERV_BESTEFFORT;
2022 efs.msdu = cpu_to_le16(chan->local_msdu);
2023 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2024 efs.acc_lat = 0;
2025 efs.flush_to = 0;
2026 break;
2027
2028 default:
2029 return;
2030 }
2031
2032 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
2033 (unsigned long) &efs);
2034}
2035
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002036static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002037{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002038 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2039 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002040
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02002041 BT_DBG("chan %p", chan);
2042
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002043 l2cap_chan_lock(chan);
2044
Szymon Jancb17e73b2012-01-11 10:59:47 +01002045 __l2cap_send_ack(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002046
2047 l2cap_chan_unlock(chan);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002048
2049 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002050}
2051
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002052static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002053{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002054 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002055 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002056 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002057 chan->num_acked = 0;
2058 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002059
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002060 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2061 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2062 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002063
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002064 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002065
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002066 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002067}
2068
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002069static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2070{
2071 switch (mode) {
2072 case L2CAP_MODE_STREAMING:
2073 case L2CAP_MODE_ERTM:
2074 if (l2cap_mode_supported(mode, remote_feat_mask))
2075 return mode;
2076 /* fall through */
2077 default:
2078 return L2CAP_MODE_BASIC;
2079 }
2080}
2081
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002082static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2083{
2084 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2085}
2086
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002087static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2088{
2089 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2090}
2091
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002092static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2093{
2094 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002095 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002096 /* use extended control field */
2097 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002098 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2099 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002100 chan->tx_win = min_t(u16, chan->tx_win,
2101 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002102 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2103 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002104}
2105
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002106static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002109 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002111 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002113 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002115 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002116 goto done;
2117
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002118 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002119 case L2CAP_MODE_STREAMING:
2120 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002121 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002122 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002123
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002124 if (__l2cap_efs_supported(chan))
2125 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2126
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002127 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002128 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002129 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002130 break;
2131 }
2132
2133done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002134 if (chan->imtu != L2CAP_DEFAULT_MTU)
2135 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002136
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002137 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002138 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002139 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2140 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002141 break;
2142
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002143 rfc.mode = L2CAP_MODE_BASIC;
2144 rfc.txwin_size = 0;
2145 rfc.max_transmit = 0;
2146 rfc.retrans_timeout = 0;
2147 rfc.monitor_timeout = 0;
2148 rfc.max_pdu_size = 0;
2149
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002150 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2151 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002152 break;
2153
2154 case L2CAP_MODE_ERTM:
2155 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002156 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002157 rfc.retrans_timeout = 0;
2158 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002159
2160 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2161 L2CAP_EXT_HDR_SIZE -
2162 L2CAP_SDULEN_SIZE -
2163 L2CAP_FCS_SIZE);
2164 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002165
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002166 l2cap_txwin_setup(chan);
2167
2168 rfc.txwin_size = min_t(u16, chan->tx_win,
2169 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002170
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002171 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2172 (unsigned long) &rfc);
2173
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002174 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2175 l2cap_add_opt_efs(&ptr, chan);
2176
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002177 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002178 break;
2179
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002180 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002181 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002182 chan->fcs = L2CAP_FCS_NONE;
2183 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002184 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002185
2186 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2187 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2188 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002189 break;
2190
2191 case L2CAP_MODE_STREAMING:
2192 rfc.mode = L2CAP_MODE_STREAMING;
2193 rfc.txwin_size = 0;
2194 rfc.max_transmit = 0;
2195 rfc.retrans_timeout = 0;
2196 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002197
2198 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2199 L2CAP_EXT_HDR_SIZE -
2200 L2CAP_SDULEN_SIZE -
2201 L2CAP_FCS_SIZE);
2202 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002203
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002204 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2205 (unsigned long) &rfc);
2206
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002207 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2208 l2cap_add_opt_efs(&ptr, chan);
2209
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002210 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002211 break;
2212
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002213 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002214 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002215 chan->fcs = L2CAP_FCS_NONE;
2216 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002217 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002218 break;
2219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002221 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002222 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223
2224 return ptr - data;
2225}
2226
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002227static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002229 struct l2cap_conf_rsp *rsp = data;
2230 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002231 void *req = chan->conf_req;
2232 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002233 int type, hint, olen;
2234 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002235 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002236 struct l2cap_conf_efs efs;
2237 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002238 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002239 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002240 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002242 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002243
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002244 while (len >= L2CAP_CONF_OPT_SIZE) {
2245 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002247 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002248 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002249
2250 switch (type) {
2251 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002252 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002253 break;
2254
2255 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002256 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002257 break;
2258
2259 case L2CAP_CONF_QOS:
2260 break;
2261
Marcel Holtmann6464f352007-10-20 13:39:51 +02002262 case L2CAP_CONF_RFC:
2263 if (olen == sizeof(rfc))
2264 memcpy(&rfc, (void *) val, olen);
2265 break;
2266
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002267 case L2CAP_CONF_FCS:
2268 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002269 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002270 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002271
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002272 case L2CAP_CONF_EFS:
2273 remote_efs = 1;
2274 if (olen == sizeof(efs))
2275 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002276 break;
2277
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002278 case L2CAP_CONF_EWS:
2279 if (!enable_hs)
2280 return -ECONNREFUSED;
2281
2282 set_bit(FLAG_EXT_CTRL, &chan->flags);
2283 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002284 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002285 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002286 break;
2287
2288 default:
2289 if (hint)
2290 break;
2291
2292 result = L2CAP_CONF_UNKNOWN;
2293 *((u8 *) ptr++) = type;
2294 break;
2295 }
2296 }
2297
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002298 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002299 goto done;
2300
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002301 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002302 case L2CAP_MODE_STREAMING:
2303 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002304 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002305 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002306 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002307 break;
2308 }
2309
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002310 if (remote_efs) {
2311 if (__l2cap_efs_supported(chan))
2312 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2313 else
2314 return -ECONNREFUSED;
2315 }
2316
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002317 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002318 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002319
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002320 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002321 }
2322
2323done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002324 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002325 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002326 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002327
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002328 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002329 return -ECONNREFUSED;
2330
2331 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2332 sizeof(rfc), (unsigned long) &rfc);
2333 }
2334
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002335 if (result == L2CAP_CONF_SUCCESS) {
2336 /* Configure output options and let the other side know
2337 * which ones we don't like. */
2338
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002339 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2340 result = L2CAP_CONF_UNACCEPT;
2341 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002342 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002343 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002344 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002345 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002346
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002347 if (remote_efs) {
2348 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2349 efs.stype != L2CAP_SERV_NOTRAFIC &&
2350 efs.stype != chan->local_stype) {
2351
2352 result = L2CAP_CONF_UNACCEPT;
2353
2354 if (chan->num_conf_req >= 1)
2355 return -ECONNREFUSED;
2356
2357 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002358 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002359 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002360 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002361 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002362 result = L2CAP_CONF_PENDING;
2363 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002364 }
2365 }
2366
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002367 switch (rfc.mode) {
2368 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002369 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002370 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002371 break;
2372
2373 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002374 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2375 chan->remote_tx_win = rfc.txwin_size;
2376 else
2377 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2378
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002379 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002380
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002381 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2382 chan->conn->mtu -
2383 L2CAP_EXT_HDR_SIZE -
2384 L2CAP_SDULEN_SIZE -
2385 L2CAP_FCS_SIZE);
2386 rfc.max_pdu_size = cpu_to_le16(size);
2387 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002388
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002389 rfc.retrans_timeout =
Andrei Emeltchenko4fd21a82012-03-12 12:13:10 +02002390 __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002391 rfc.monitor_timeout =
Andrei Emeltchenko4fd21a82012-03-12 12:13:10 +02002392 __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002393
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002394 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002395
2396 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2397 sizeof(rfc), (unsigned long) &rfc);
2398
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002399 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2400 chan->remote_id = efs.id;
2401 chan->remote_stype = efs.stype;
2402 chan->remote_msdu = le16_to_cpu(efs.msdu);
2403 chan->remote_flush_to =
2404 le32_to_cpu(efs.flush_to);
2405 chan->remote_acc_lat =
2406 le32_to_cpu(efs.acc_lat);
2407 chan->remote_sdu_itime =
2408 le32_to_cpu(efs.sdu_itime);
2409 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2410 sizeof(efs), (unsigned long) &efs);
2411 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002412 break;
2413
2414 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002415 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2416 chan->conn->mtu -
2417 L2CAP_EXT_HDR_SIZE -
2418 L2CAP_SDULEN_SIZE -
2419 L2CAP_FCS_SIZE);
2420 rfc.max_pdu_size = cpu_to_le16(size);
2421 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002422
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002423 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002424
2425 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2426 sizeof(rfc), (unsigned long) &rfc);
2427
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002428 break;
2429
2430 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002431 result = L2CAP_CONF_UNACCEPT;
2432
2433 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002434 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002435 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002436
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002437 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002438 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002439 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002440 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002441 rsp->result = cpu_to_le16(result);
2442 rsp->flags = cpu_to_le16(0x0000);
2443
2444 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445}
2446
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002447static 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 -03002448{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002449 struct l2cap_conf_req *req = data;
2450 void *ptr = req->data;
2451 int type, olen;
2452 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002453 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002454 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002455
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002456 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002457
2458 while (len >= L2CAP_CONF_OPT_SIZE) {
2459 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2460
2461 switch (type) {
2462 case L2CAP_CONF_MTU:
2463 if (val < L2CAP_DEFAULT_MIN_MTU) {
2464 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002465 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002466 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002467 chan->imtu = val;
2468 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002469 break;
2470
2471 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002472 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002473 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002474 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002475 break;
2476
2477 case L2CAP_CONF_RFC:
2478 if (olen == sizeof(rfc))
2479 memcpy(&rfc, (void *)val, olen);
2480
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002481 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002482 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002483 return -ECONNREFUSED;
2484
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002485 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002486
2487 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2488 sizeof(rfc), (unsigned long) &rfc);
2489 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002490
2491 case L2CAP_CONF_EWS:
2492 chan->tx_win = min_t(u16, val,
2493 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002494 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2495 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002496 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002497
2498 case L2CAP_CONF_EFS:
2499 if (olen == sizeof(efs))
2500 memcpy(&efs, (void *)val, olen);
2501
2502 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2503 efs.stype != L2CAP_SERV_NOTRAFIC &&
2504 efs.stype != chan->local_stype)
2505 return -ECONNREFUSED;
2506
2507 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2508 sizeof(efs), (unsigned long) &efs);
2509 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002510 }
2511 }
2512
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002513 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002514 return -ECONNREFUSED;
2515
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002516 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002517
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002518 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002519 switch (rfc.mode) {
2520 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002521 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2522 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2523 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002524
2525 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2526 chan->local_msdu = le16_to_cpu(efs.msdu);
2527 chan->local_sdu_itime =
2528 le32_to_cpu(efs.sdu_itime);
2529 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2530 chan->local_flush_to =
2531 le32_to_cpu(efs.flush_to);
2532 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002533 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002534
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002535 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002536 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002537 }
2538 }
2539
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002540 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002541 req->flags = cpu_to_le16(0x0000);
2542
2543 return ptr - data;
2544}
2545
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002546static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547{
2548 struct l2cap_conf_rsp *rsp = data;
2549 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002551 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002553 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002554 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002555 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556
2557 return ptr - data;
2558}
2559
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002560void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002561{
2562 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002563 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002564 u8 buf[128];
2565
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002566 rsp.scid = cpu_to_le16(chan->dcid);
2567 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002568 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2569 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2570 l2cap_send_cmd(conn, chan->ident,
2571 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2572
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002573 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002574 return;
2575
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002576 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2577 l2cap_build_conf_req(chan, buf), buf);
2578 chan->num_conf_req++;
2579}
2580
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002581static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002582{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002583 int type, olen;
2584 unsigned long val;
2585 struct l2cap_conf_rfc rfc;
2586
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002587 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002588
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002589 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002590 return;
2591
2592 while (len >= L2CAP_CONF_OPT_SIZE) {
2593 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2594
2595 switch (type) {
2596 case L2CAP_CONF_RFC:
2597 if (olen == sizeof(rfc))
2598 memcpy(&rfc, (void *)val, olen);
2599 goto done;
2600 }
2601 }
2602
Mat Martineau36e999a2011-12-08 17:23:21 -08002603 /* Use sane default values in case a misbehaving remote device
2604 * did not send an RFC option.
2605 */
2606 rfc.mode = chan->mode;
2607 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2608 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2609 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2610
2611 BT_ERR("Expected RFC option was not found, using defaults");
2612
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002613done:
2614 switch (rfc.mode) {
2615 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002616 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2617 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2618 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002619 break;
2620 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002621 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002622 }
2623}
2624
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002625static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2626{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002627 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002628
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002629 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002630 return 0;
2631
2632 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2633 cmd->ident == conn->info_ident) {
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02002634 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002635
2636 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002637 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002638
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002639 l2cap_conn_start(conn);
2640 }
2641
2642 return 0;
2643}
2644
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2646{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2648 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002649 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002650 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002651 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652
2653 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002654 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
Andrei Emeltchenko097db762012-03-09 14:16:17 +02002656 BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
2658 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002659 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2660 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 result = L2CAP_CR_BAD_PSM;
2662 goto sendresp;
2663 }
2664
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002665 parent = pchan->sk;
2666
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002667 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002668 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002669
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002670 /* Check if the ACL is secure enough (if not SDP) */
2671 if (psm != cpu_to_le16(0x0001) &&
2672 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002673 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002674 result = L2CAP_CR_SEC_BLOCK;
2675 goto response;
2676 }
2677
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 result = L2CAP_CR_NO_MEM;
2679
2680 /* Check for backlog size */
2681 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002682 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 goto response;
2684 }
2685
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002686 chan = pchan->ops->new_connection(pchan->data);
2687 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 goto response;
2689
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002690 sk = chan->sk;
2691
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002693 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002695 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 goto response;
2697 }
2698
2699 hci_conn_hold(conn->hcon);
2700
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 bacpy(&bt_sk(sk)->src, conn->src);
2702 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002703 chan->psm = psm;
2704 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002706 bt_accept_enqueue(parent, sk);
2707
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002708 __l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002709
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002710 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002712 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002714 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715
Marcel Holtmann984947d2009-02-06 23:35:19 +01002716 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002717 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002718 if (bt_sk(sk)->defer_setup) {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002719 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002720 result = L2CAP_CR_PEND;
2721 status = L2CAP_CS_AUTHOR_PEND;
2722 parent->sk_data_ready(parent, 0);
2723 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002724 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002725 result = L2CAP_CR_SUCCESS;
2726 status = L2CAP_CS_NO_INFO;
2727 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002728 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002729 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002730 result = L2CAP_CR_PEND;
2731 status = L2CAP_CS_AUTHEN_PEND;
2732 }
2733 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002734 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002735 result = L2CAP_CR_PEND;
2736 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 }
2738
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002740 release_sock(parent);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002741 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742
2743sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002744 rsp.scid = cpu_to_le16(scid);
2745 rsp.dcid = cpu_to_le16(dcid);
2746 rsp.result = cpu_to_le16(result);
2747 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002749
2750 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2751 struct l2cap_info_req info;
2752 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2753
2754 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2755 conn->info_ident = l2cap_get_ident(conn);
2756
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08002757 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002758
2759 l2cap_send_cmd(conn, conn->info_ident,
2760 L2CAP_INFO_REQ, sizeof(info), &info);
2761 }
2762
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002763 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002764 result == L2CAP_CR_SUCCESS) {
2765 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002766 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002767 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002768 l2cap_build_conf_req(chan, buf), buf);
2769 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002770 }
2771
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 return 0;
2773}
2774
2775static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2776{
2777 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2778 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002779 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 u8 req[128];
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002781 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
2783 scid = __le16_to_cpu(rsp->scid);
2784 dcid = __le16_to_cpu(rsp->dcid);
2785 result = __le16_to_cpu(rsp->result);
2786 status = __le16_to_cpu(rsp->status);
2787
Andrei Emeltchenko1b009c92012-02-21 12:54:54 +02002788 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
2789 dcid, scid, result, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002791 mutex_lock(&conn->chan_lock);
2792
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 if (scid) {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002794 chan = __l2cap_get_chan_by_scid(conn, scid);
2795 if (!chan) {
2796 err = -EFAULT;
2797 goto unlock;
2798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 } else {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002800 chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
2801 if (!chan) {
2802 err = -EFAULT;
2803 goto unlock;
2804 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 }
2806
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002807 err = 0;
2808
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002809 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002810
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 switch (result) {
2812 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002813 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002814 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002815 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002816 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002817
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002818 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002819 break;
2820
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002822 l2cap_build_conf_req(chan, req), req);
2823 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 break;
2825
2826 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002827 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 break;
2829
2830 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002831 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 break;
2833 }
2834
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002835 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002836
2837unlock:
2838 mutex_unlock(&conn->chan_lock);
2839
2840 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841}
2842
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002843static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002844{
2845 /* FCS is enabled only in ERTM or streaming mode, if one or both
2846 * sides request it.
2847 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002848 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002849 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002850 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002851 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002852}
2853
Al Viro88219a02007-07-29 00:17:25 -07002854static 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 -07002855{
2856 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2857 u16 dcid, flags;
2858 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002859 struct l2cap_chan *chan;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002860 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
2862 dcid = __le16_to_cpu(req->dcid);
2863 flags = __le16_to_cpu(req->flags);
2864
2865 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2866
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002867 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002868 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 return -ENOENT;
2870
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002871 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002872
David S. Miller033b1142011-07-21 13:38:42 -07002873 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002874 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002875
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002876 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2877 rej.scid = cpu_to_le16(chan->scid);
2878 rej.dcid = cpu_to_le16(chan->dcid);
2879
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002880 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2881 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002882 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002883 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002884
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002885 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002886 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002887 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002888 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002889 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002890 L2CAP_CONF_REJECT, flags), rsp);
2891 goto unlock;
2892 }
2893
2894 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002895 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2896 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897
2898 if (flags & 0x0001) {
2899 /* Incomplete config. Send empty response. */
2900 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002901 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002902 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 goto unlock;
2904 }
2905
2906 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002907 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002908 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002909 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002913 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002914 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002915
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002916 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002917 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002918
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002919 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002920 goto unlock;
2921
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002922 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002923 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002924
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002925 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002926
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002927 chan->next_tx_seq = 0;
2928 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002929 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002930 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002931 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002932
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02002933 l2cap_chan_ready(chan);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002934 goto unlock;
2935 }
2936
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002937 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002938 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002939 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002940 l2cap_build_conf_req(chan, buf), buf);
2941 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942 }
2943
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002944 /* Got Conf Rsp PENDING from remote side and asume we sent
2945 Conf Rsp PENDING in the code above */
2946 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2947 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2948
2949 /* check compatibility */
2950
2951 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2952 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2953
2954 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002955 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002956 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2957 }
2958
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959unlock:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002960 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 return 0;
2962}
2963
2964static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2965{
2966 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2967 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002968 struct l2cap_chan *chan;
Andrei Emeltchenko61386cb2012-03-12 12:13:07 +02002969 int len = le16_to_cpu(cmd->len) - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970
2971 scid = __le16_to_cpu(rsp->scid);
2972 flags = __le16_to_cpu(rsp->flags);
2973 result = __le16_to_cpu(rsp->result);
2974
Andrei Emeltchenko61386cb2012-03-12 12:13:07 +02002975 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x len %d", scid, flags,
2976 result, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002978 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002979 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 return 0;
2981
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002982 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002983
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 switch (result) {
2985 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002986 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002987 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 break;
2989
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002990 case L2CAP_CONF_PENDING:
2991 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2992
2993 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2994 char buf[64];
2995
2996 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2997 buf, &result);
2998 if (len < 0) {
2999 l2cap_send_disconn_req(conn, chan, ECONNRESET);
3000 goto done;
3001 }
3002
3003 /* check compatibility */
3004
3005 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
3006 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
3007
3008 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02003009 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03003010 L2CAP_CONF_SUCCESS, 0x0000), buf);
3011 }
3012 goto done;
3013
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003015 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003016 char req[64];
3017
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003018 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003019 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003020 goto done;
3021 }
3022
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003023 /* throw out any old stored conf requests */
3024 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03003025 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
3026 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003027 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003028 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003029 goto done;
3030 }
3031
3032 l2cap_send_cmd(conn, l2cap_get_ident(conn),
3033 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003034 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003035 if (result != L2CAP_CONF_SUCCESS)
3036 goto done;
3037 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 }
3039
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09003040 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003041 l2cap_chan_set_err(chan, ECONNRESET);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +02003042
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08003043 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003044 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 goto done;
3046 }
3047
3048 if (flags & 0x01)
3049 goto done;
3050
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003051 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003053 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003054 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003055
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003056 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003057 chan->next_tx_seq = 0;
3058 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003059 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003060 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003061 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003062
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02003063 l2cap_chan_ready(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 }
3065
3066done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003067 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 return 0;
3069}
3070
3071static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3072{
3073 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3074 struct l2cap_disconn_rsp rsp;
3075 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003076 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077 struct sock *sk;
3078
3079 scid = __le16_to_cpu(req->scid);
3080 dcid = __le16_to_cpu(req->dcid);
3081
3082 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3083
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003084 mutex_lock(&conn->chan_lock);
3085
3086 chan = __l2cap_get_chan_by_scid(conn, dcid);
3087 if (!chan) {
3088 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003092 l2cap_chan_lock(chan);
3093
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003094 sk = chan->sk;
3095
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003096 rsp.dcid = cpu_to_le16(chan->scid);
3097 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3099
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003100 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 sk->sk_shutdown = SHUTDOWN_MASK;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003102 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003104 l2cap_chan_del(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003105
3106 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003108 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003109
3110 mutex_unlock(&conn->chan_lock);
3111
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112 return 0;
3113}
3114
3115static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3116{
3117 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3118 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003119 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120
3121 scid = __le16_to_cpu(rsp->scid);
3122 dcid = __le16_to_cpu(rsp->dcid);
3123
3124 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3125
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003126 mutex_lock(&conn->chan_lock);
3127
3128 chan = __l2cap_get_chan_by_scid(conn, scid);
3129 if (!chan) {
3130 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003134 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003135
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003136 l2cap_chan_del(chan, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003137
3138 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003140 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003141
3142 mutex_unlock(&conn->chan_lock);
3143
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 return 0;
3145}
3146
3147static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3148{
3149 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 u16 type;
3151
3152 type = __le16_to_cpu(req->type);
3153
3154 BT_DBG("type 0x%4.4x", type);
3155
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003156 if (type == L2CAP_IT_FEAT_MASK) {
3157 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003158 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003159 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3160 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3161 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003162 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003163 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3164 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003165 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003166 feat_mask |= L2CAP_FEAT_EXT_FLOW
3167 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003168
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003169 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003170 l2cap_send_cmd(conn, cmd->ident,
3171 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003172 } else if (type == L2CAP_IT_FIXED_CHAN) {
3173 u8 buf[12];
3174 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003175
3176 if (enable_hs)
3177 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3178 else
3179 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3180
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003181 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3182 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003183 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003184 l2cap_send_cmd(conn, cmd->ident,
3185 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003186 } else {
3187 struct l2cap_info_rsp rsp;
3188 rsp.type = cpu_to_le16(type);
3189 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3190 l2cap_send_cmd(conn, cmd->ident,
3191 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193
3194 return 0;
3195}
3196
3197static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3198{
3199 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3200 u16 type, result;
3201
3202 type = __le16_to_cpu(rsp->type);
3203 result = __le16_to_cpu(rsp->result);
3204
3205 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3206
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003207 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3208 if (cmd->ident != conn->info_ident ||
3209 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3210 return 0;
3211
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02003212 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003213
Ville Tervoadb08ed2010-08-04 09:43:33 +03003214 if (result != L2CAP_IR_SUCCESS) {
3215 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3216 conn->info_ident = 0;
3217
3218 l2cap_conn_start(conn);
3219
3220 return 0;
3221 }
3222
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003223 switch (type) {
3224 case L2CAP_IT_FEAT_MASK:
Harvey Harrison83985312008-05-02 16:25:46 -07003225 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003226
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003227 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003228 struct l2cap_info_req req;
3229 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3230
3231 conn->info_ident = l2cap_get_ident(conn);
3232
3233 l2cap_send_cmd(conn, conn->info_ident,
3234 L2CAP_INFO_REQ, sizeof(req), &req);
3235 } else {
3236 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3237 conn->info_ident = 0;
3238
3239 l2cap_conn_start(conn);
3240 }
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003241 break;
3242
3243 case L2CAP_IT_FIXED_CHAN:
3244 conn->fixed_chan_mask = rsp->data[0];
Marcel Holtmann984947d2009-02-06 23:35:19 +01003245 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003246 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003247
3248 l2cap_conn_start(conn);
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003249 break;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003250 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003251
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 return 0;
3253}
3254
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003255static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3256 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3257 void *data)
3258{
3259 struct l2cap_create_chan_req *req = data;
3260 struct l2cap_create_chan_rsp rsp;
3261 u16 psm, scid;
3262
3263 if (cmd_len != sizeof(*req))
3264 return -EPROTO;
3265
3266 if (!enable_hs)
3267 return -EINVAL;
3268
3269 psm = le16_to_cpu(req->psm);
3270 scid = le16_to_cpu(req->scid);
3271
3272 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3273
3274 /* Placeholder: Always reject */
3275 rsp.dcid = 0;
3276 rsp.scid = cpu_to_le16(scid);
Andrei Emeltchenko8ce0c492012-03-12 12:13:09 +02003277 rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
3278 rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003279
3280 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3281 sizeof(rsp), &rsp);
3282
3283 return 0;
3284}
3285
3286static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3287 struct l2cap_cmd_hdr *cmd, void *data)
3288{
3289 BT_DBG("conn %p", conn);
3290
3291 return l2cap_connect_rsp(conn, cmd, data);
3292}
3293
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003294static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3295 u16 icid, u16 result)
3296{
3297 struct l2cap_move_chan_rsp rsp;
3298
3299 BT_DBG("icid %d, result %d", icid, result);
3300
3301 rsp.icid = cpu_to_le16(icid);
3302 rsp.result = cpu_to_le16(result);
3303
3304 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3305}
3306
3307static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3308 struct l2cap_chan *chan, u16 icid, u16 result)
3309{
3310 struct l2cap_move_chan_cfm cfm;
3311 u8 ident;
3312
3313 BT_DBG("icid %d, result %d", icid, result);
3314
3315 ident = l2cap_get_ident(conn);
3316 if (chan)
3317 chan->ident = ident;
3318
3319 cfm.icid = cpu_to_le16(icid);
3320 cfm.result = cpu_to_le16(result);
3321
3322 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3323}
3324
3325static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3326 u16 icid)
3327{
3328 struct l2cap_move_chan_cfm_rsp rsp;
3329
3330 BT_DBG("icid %d", icid);
3331
3332 rsp.icid = cpu_to_le16(icid);
3333 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3334}
3335
3336static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3337 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3338{
3339 struct l2cap_move_chan_req *req = data;
3340 u16 icid = 0;
3341 u16 result = L2CAP_MR_NOT_ALLOWED;
3342
3343 if (cmd_len != sizeof(*req))
3344 return -EPROTO;
3345
3346 icid = le16_to_cpu(req->icid);
3347
3348 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3349
3350 if (!enable_hs)
3351 return -EINVAL;
3352
3353 /* Placeholder: Always refuse */
3354 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3355
3356 return 0;
3357}
3358
3359static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3360 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3361{
3362 struct l2cap_move_chan_rsp *rsp = data;
3363 u16 icid, result;
3364
3365 if (cmd_len != sizeof(*rsp))
3366 return -EPROTO;
3367
3368 icid = le16_to_cpu(rsp->icid);
3369 result = le16_to_cpu(rsp->result);
3370
3371 BT_DBG("icid %d, result %d", icid, result);
3372
3373 /* Placeholder: Always unconfirmed */
3374 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3375
3376 return 0;
3377}
3378
3379static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3380 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3381{
3382 struct l2cap_move_chan_cfm *cfm = data;
3383 u16 icid, result;
3384
3385 if (cmd_len != sizeof(*cfm))
3386 return -EPROTO;
3387
3388 icid = le16_to_cpu(cfm->icid);
3389 result = le16_to_cpu(cfm->result);
3390
3391 BT_DBG("icid %d, result %d", icid, result);
3392
3393 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3394
3395 return 0;
3396}
3397
3398static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3399 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3400{
3401 struct l2cap_move_chan_cfm_rsp *rsp = data;
3402 u16 icid;
3403
3404 if (cmd_len != sizeof(*rsp))
3405 return -EPROTO;
3406
3407 icid = le16_to_cpu(rsp->icid);
3408
3409 BT_DBG("icid %d", icid);
3410
3411 return 0;
3412}
3413
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003414static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003415 u16 to_multiplier)
3416{
3417 u16 max_latency;
3418
3419 if (min > max || min < 6 || max > 3200)
3420 return -EINVAL;
3421
3422 if (to_multiplier < 10 || to_multiplier > 3200)
3423 return -EINVAL;
3424
3425 if (max >= to_multiplier * 8)
3426 return -EINVAL;
3427
3428 max_latency = (to_multiplier * 8 / max) - 1;
3429 if (latency > 499 || latency > max_latency)
3430 return -EINVAL;
3431
3432 return 0;
3433}
3434
3435static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3436 struct l2cap_cmd_hdr *cmd, u8 *data)
3437{
3438 struct hci_conn *hcon = conn->hcon;
3439 struct l2cap_conn_param_update_req *req;
3440 struct l2cap_conn_param_update_rsp rsp;
3441 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003442 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003443
3444 if (!(hcon->link_mode & HCI_LM_MASTER))
3445 return -EINVAL;
3446
3447 cmd_len = __le16_to_cpu(cmd->len);
3448 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3449 return -EPROTO;
3450
3451 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003452 min = __le16_to_cpu(req->min);
3453 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003454 latency = __le16_to_cpu(req->latency);
3455 to_multiplier = __le16_to_cpu(req->to_multiplier);
3456
3457 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3458 min, max, latency, to_multiplier);
3459
3460 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003461
3462 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3463 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003464 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3465 else
3466 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3467
3468 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3469 sizeof(rsp), &rsp);
3470
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003471 if (!err)
3472 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3473
Claudio Takahaside731152011-02-11 19:28:55 -02003474 return 0;
3475}
3476
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003477static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3478 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3479{
3480 int err = 0;
3481
3482 switch (cmd->code) {
3483 case L2CAP_COMMAND_REJ:
3484 l2cap_command_rej(conn, cmd, data);
3485 break;
3486
3487 case L2CAP_CONN_REQ:
3488 err = l2cap_connect_req(conn, cmd, data);
3489 break;
3490
3491 case L2CAP_CONN_RSP:
3492 err = l2cap_connect_rsp(conn, cmd, data);
3493 break;
3494
3495 case L2CAP_CONF_REQ:
3496 err = l2cap_config_req(conn, cmd, cmd_len, data);
3497 break;
3498
3499 case L2CAP_CONF_RSP:
3500 err = l2cap_config_rsp(conn, cmd, data);
3501 break;
3502
3503 case L2CAP_DISCONN_REQ:
3504 err = l2cap_disconnect_req(conn, cmd, data);
3505 break;
3506
3507 case L2CAP_DISCONN_RSP:
3508 err = l2cap_disconnect_rsp(conn, cmd, data);
3509 break;
3510
3511 case L2CAP_ECHO_REQ:
3512 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3513 break;
3514
3515 case L2CAP_ECHO_RSP:
3516 break;
3517
3518 case L2CAP_INFO_REQ:
3519 err = l2cap_information_req(conn, cmd, data);
3520 break;
3521
3522 case L2CAP_INFO_RSP:
3523 err = l2cap_information_rsp(conn, cmd, data);
3524 break;
3525
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003526 case L2CAP_CREATE_CHAN_REQ:
3527 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3528 break;
3529
3530 case L2CAP_CREATE_CHAN_RSP:
3531 err = l2cap_create_channel_rsp(conn, cmd, data);
3532 break;
3533
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003534 case L2CAP_MOVE_CHAN_REQ:
3535 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3536 break;
3537
3538 case L2CAP_MOVE_CHAN_RSP:
3539 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3540 break;
3541
3542 case L2CAP_MOVE_CHAN_CFM:
3543 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3544 break;
3545
3546 case L2CAP_MOVE_CHAN_CFM_RSP:
3547 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3548 break;
3549
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003550 default:
3551 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3552 err = -EINVAL;
3553 break;
3554 }
3555
3556 return err;
3557}
3558
3559static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3560 struct l2cap_cmd_hdr *cmd, u8 *data)
3561{
3562 switch (cmd->code) {
3563 case L2CAP_COMMAND_REJ:
3564 return 0;
3565
3566 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003567 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003568
3569 case L2CAP_CONN_PARAM_UPDATE_RSP:
3570 return 0;
3571
3572 default:
3573 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3574 return -EINVAL;
3575 }
3576}
3577
3578static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3579 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580{
3581 u8 *data = skb->data;
3582 int len = skb->len;
3583 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003584 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585
3586 l2cap_raw_recv(conn, skb);
3587
3588 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003589 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3591 data += L2CAP_CMD_HDR_SIZE;
3592 len -= L2CAP_CMD_HDR_SIZE;
3593
Al Viro88219a02007-07-29 00:17:25 -07003594 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595
Al Viro88219a02007-07-29 00:17:25 -07003596 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 -07003597
Al Viro88219a02007-07-29 00:17:25 -07003598 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 BT_DBG("corrupted command");
3600 break;
3601 }
3602
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003603 if (conn->hcon->type == LE_LINK)
3604 err = l2cap_le_sig_cmd(conn, &cmd, data);
3605 else
3606 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607
3608 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003609 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003610
3611 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612
3613 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003614 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3616 }
3617
Al Viro88219a02007-07-29 00:17:25 -07003618 data += cmd_len;
3619 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 }
3621
3622 kfree_skb(skb);
3623}
3624
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003625static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003626{
3627 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003628 int hdr_size;
3629
3630 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3631 hdr_size = L2CAP_EXT_HDR_SIZE;
3632 else
3633 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003634
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003635 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003636 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003637 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3638 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3639
3640 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003641 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003642 }
3643 return 0;
3644}
3645
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003646static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003647{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003648 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003649
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003650 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003651
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003652 control |= __set_reqseq(chan, chan->buffer_seq);
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)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003655 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003656 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003657 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003658 }
3659
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003660 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003661 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003662
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003663 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003664
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003665 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003666 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003667 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003668 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003669 }
3670}
3671
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003672static 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 -03003673{
3674 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003675 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003676
3677 bt_cb(skb)->tx_seq = tx_seq;
3678 bt_cb(skb)->sar = sar;
3679
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003680 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003681
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003682 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003683
Szymon Janc039d9572011-11-16 09:32:19 +01003684 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003685 if (bt_cb(next_skb)->tx_seq == tx_seq)
3686 return -EINVAL;
3687
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003688 next_tx_seq_offset = __seq_offset(chan,
3689 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003690
3691 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003692 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003693 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003694 }
3695
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003696 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003697 next_skb = NULL;
3698 else
3699 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3700 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003701
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003702 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003703
3704 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003705}
3706
Mat Martineau84084a32011-07-22 14:54:00 -07003707static void append_skb_frag(struct sk_buff *skb,
3708 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003709{
Mat Martineau84084a32011-07-22 14:54:00 -07003710 /* skb->len reflects data in skb as well as all fragments
3711 * skb->data_len reflects only data in fragments
3712 */
3713 if (!skb_has_frag_list(skb))
3714 skb_shinfo(skb)->frag_list = new_frag;
3715
3716 new_frag->next = NULL;
3717
3718 (*last_frag)->next = new_frag;
3719 *last_frag = new_frag;
3720
3721 skb->len += new_frag->len;
3722 skb->data_len += new_frag->len;
3723 skb->truesize += new_frag->truesize;
3724}
3725
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003726static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003727{
3728 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003729
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003730 switch (__get_ctrl_sar(chan, control)) {
3731 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003732 if (chan->sdu)
3733 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003734
Mat Martineau84084a32011-07-22 14:54:00 -07003735 err = chan->ops->recv(chan->data, skb);
3736 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003737
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003738 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003739 if (chan->sdu)
3740 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003741
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003742 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003743 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003744
Mat Martineau84084a32011-07-22 14:54:00 -07003745 if (chan->sdu_len > chan->imtu) {
3746 err = -EMSGSIZE;
3747 break;
3748 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003749
Mat Martineau84084a32011-07-22 14:54:00 -07003750 if (skb->len >= chan->sdu_len)
3751 break;
3752
3753 chan->sdu = skb;
3754 chan->sdu_last_frag = skb;
3755
3756 skb = NULL;
3757 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003758 break;
3759
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003760 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003761 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003762 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003763
Mat Martineau84084a32011-07-22 14:54:00 -07003764 append_skb_frag(chan->sdu, skb,
3765 &chan->sdu_last_frag);
3766 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003767
Mat Martineau84084a32011-07-22 14:54:00 -07003768 if (chan->sdu->len >= chan->sdu_len)
3769 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003770
Mat Martineau84084a32011-07-22 14:54:00 -07003771 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003772 break;
3773
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003774 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003775 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003776 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003777
Mat Martineau84084a32011-07-22 14:54:00 -07003778 append_skb_frag(chan->sdu, skb,
3779 &chan->sdu_last_frag);
3780 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003781
Mat Martineau84084a32011-07-22 14:54:00 -07003782 if (chan->sdu->len != chan->sdu_len)
3783 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003784
Mat Martineau84084a32011-07-22 14:54:00 -07003785 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003786
Mat Martineau84084a32011-07-22 14:54:00 -07003787 if (!err) {
3788 /* Reassembly complete */
3789 chan->sdu = NULL;
3790 chan->sdu_last_frag = NULL;
3791 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003792 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003793 break;
3794 }
3795
Mat Martineau84084a32011-07-22 14:54:00 -07003796 if (err) {
3797 kfree_skb(skb);
3798 kfree_skb(chan->sdu);
3799 chan->sdu = NULL;
3800 chan->sdu_last_frag = NULL;
3801 chan->sdu_len = 0;
3802 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003803
Mat Martineau84084a32011-07-22 14:54:00 -07003804 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003805}
3806
Mat Martineau26f880d2011-07-07 09:39:01 -07003807static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003808{
Mat Martineau26f880d2011-07-07 09:39:01 -07003809 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003810
Mat Martineau26f880d2011-07-07 09:39:01 -07003811 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3812
Szymon Janc77f918b2012-01-11 10:59:48 +01003813 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003814}
3815
3816static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3817{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003818 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003819
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003820 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003821 goto done;
3822
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003823 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003824 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003825 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003826 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003827 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003828
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003829 __clear_retrans_timer(chan);
3830 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003831
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003832 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003833
3834done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003835 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3836 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003837
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003838 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003839}
3840
Mat Martineaue3281402011-07-07 09:39:02 -07003841void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003842{
Mat Martineaue3281402011-07-07 09:39:02 -07003843 if (chan->mode == L2CAP_MODE_ERTM) {
3844 if (busy)
3845 l2cap_ertm_enter_local_busy(chan);
3846 else
3847 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003848 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003849}
3850
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003851static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003852{
3853 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003854 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003855
Mat Martineaue3281402011-07-07 09:39:02 -07003856 while ((skb = skb_peek(&chan->srej_q)) &&
3857 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3858 int err;
3859
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003860 if (bt_cb(skb)->tx_seq != tx_seq)
3861 break;
3862
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003863 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003864 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003865 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003866
3867 if (err < 0) {
3868 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3869 break;
3870 }
3871
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003872 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3873 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003874 }
3875}
3876
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003877static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003878{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003879 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003880 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003881
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003882 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003883 if (l->tx_seq == tx_seq) {
3884 list_del(&l->list);
3885 kfree(l);
3886 return;
3887 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003888 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003889 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003890 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003891 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003892 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003893 }
3894}
3895
Szymon Jancaef89f22011-11-16 09:32:18 +01003896static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003897{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003898 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003899 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003900
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003901 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003902 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003903 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003904 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003905
3906 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003907 if (!new)
3908 return -ENOMEM;
3909
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003910 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003911
3912 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3913
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003914 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003915 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003916
3917 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003918
3919 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003920}
3921
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003922static 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 -03003923{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003924 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003925 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003926 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003927 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003928 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003929 int err = 0;
3930
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003931 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 -03003932 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003933
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003934 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003935 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003936 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003937 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003938 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003939 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003940 }
3941
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003942 chan->expected_ack_seq = req_seq;
3943 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003944
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003945 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003946
3947 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003948 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003949 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003950 goto drop;
3951 }
3952
Szymon Janc77f918b2012-01-11 10:59:48 +01003953 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3954 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3955 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003956 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003957 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003958
Mat Martineau02f1b642011-06-29 14:35:19 -07003959 if (tx_seq == chan->expected_tx_seq)
3960 goto expected;
3961
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003962 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003963 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003964
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003965 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003966 struct srej_list, list);
3967 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003968 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003969 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003970
3971 list_del(&first->list);
3972 kfree(first);
3973
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003974 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003975 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003976 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003977 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003978 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003979 }
3980 } else {
3981 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003982
3983 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003984 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003985 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003986
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003987 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003988 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003989 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003990 return 0;
3991 }
3992 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003993
3994 err = l2cap_send_srejframe(chan, tx_seq);
3995 if (err < 0) {
3996 l2cap_send_disconn_req(chan->conn, chan, -err);
3997 return err;
3998 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003999 }
4000 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004001 expected_tx_seq_offset = __seq_offset(chan,
4002 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03004003
4004 /* duplicated tx_seq */
4005 if (tx_seq_offset < expected_tx_seq_offset)
4006 goto drop;
4007
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004008 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004009
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004010 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004011
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03004012 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004013 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004014
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004015 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004016 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004017
Szymon Janc0ef3ef02012-01-11 10:59:46 +01004018 /* Set P-bit only if there are some I-frames to ack. */
4019 if (__clear_ack_timer(chan))
4020 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03004021
Szymon Jancaef89f22011-11-16 09:32:18 +01004022 err = l2cap_send_srejframe(chan, tx_seq);
4023 if (err < 0) {
4024 l2cap_send_disconn_req(chan->conn, chan, -err);
4025 return err;
4026 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004027 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004028 return 0;
4029
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004030expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004031 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004032
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004033 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03004034 bt_cb(skb)->tx_seq = tx_seq;
4035 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004036 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004037 return 0;
4038 }
4039
Mat Martineau84084a32011-07-22 14:54:00 -07004040 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004041 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4042
Mat Martineaue3281402011-07-07 09:39:02 -07004043 if (err < 0) {
4044 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4045 return err;
4046 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03004047
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004048 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004049 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004050 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03004051 }
4052
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03004053
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004054 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
4055 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004056 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03004057 else
4058 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03004059
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004060 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03004061
4062drop:
4063 kfree_skb(skb);
4064 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004065}
4066
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004067static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004068{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004069 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004070 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004071
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004072 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004073 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004074
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004075 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004076 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4077 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4078 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004079 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004080 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004081
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004082 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004083 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004084 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004085 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004086 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004087
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004088 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004089 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004090
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004091 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004092 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004093
4094 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004095 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004096 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004097 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004098
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004099 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4100 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004101 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004102 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004103 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004104 }
4105}
4106
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004107static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004108{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004109 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004110
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004111 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004112
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004113 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004114
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004115 chan->expected_ack_seq = tx_seq;
4116 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004117
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004118 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004119 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004120 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004121 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004122 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004123
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004124 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4125 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004126 }
4127}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004128static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004129{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004130 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004131
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004132 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004133
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004134 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004135
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004136 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004137 chan->expected_ack_seq = tx_seq;
4138 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004139
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004140 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004141 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004142
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004143 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004144
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004145 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004146 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004147 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004148 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004149 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004150 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004151 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004152 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004153 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004154 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004155 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004156 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004157 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004158 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004159 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004160 }
4161 }
4162}
4163
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004164static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004165{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004166 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004167
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004168 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004169
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004170 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004171 chan->expected_ack_seq = tx_seq;
4172 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004173
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004174 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004175 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004176
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004177 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004178 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004179 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004180 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004181 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004182 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004183
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004184 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004185 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004186 } else {
4187 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4188 l2cap_send_sframe(chan, rx_control);
4189 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004190}
4191
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004192static 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 -03004193{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004194 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004195
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004196 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004197 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004198 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004199 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004200 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004201 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004202 }
4203
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004204 switch (__get_ctrl_super(chan, rx_control)) {
4205 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004206 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004207 break;
4208
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004209 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004210 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004211 break;
4212
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004213 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004214 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004215 break;
4216
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004217 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004218 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004219 break;
4220 }
4221
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004222 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004223 return 0;
4224}
4225
Szymon Janccad8f1d2012-01-23 10:06:05 +01004226static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004227{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004228 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004229 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004230 int len, next_tx_seq_offset, req_seq_offset;
4231
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004232 control = __get_control(chan, skb->data);
4233 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004234 len = skb->len;
4235
4236 /*
4237 * We can just drop the corrupted I-frame here.
4238 * Receiver will miss it and start proper recovery
4239 * procedures and ask retransmission.
4240 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004241 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004242 goto drop;
4243
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004244 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004245 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004246
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004247 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004248 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004249
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004250 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004251 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004252 goto drop;
4253 }
4254
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004255 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004256
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004257 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4258
4259 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4260 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004261
4262 /* check for invalid req-seq */
4263 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004264 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004265 goto drop;
4266 }
4267
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004268 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004269 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004270 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004271 goto drop;
4272 }
4273
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004274 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004275 } else {
4276 if (len != 0) {
4277 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004278 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004279 goto drop;
4280 }
4281
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004282 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004283 }
4284
4285 return 0;
4286
4287drop:
4288 kfree_skb(skb);
4289 return 0;
4290}
4291
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4293{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004294 struct l2cap_chan *chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004295 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004296 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004297 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004299 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004300 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 BT_DBG("unknown cid 0x%4.4x", cid);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004302 /* Drop packet and return */
Dan Carpenter33790132012-02-28 09:52:46 +03004303 kfree_skb(skb);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004304 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 }
4306
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004307 l2cap_chan_lock(chan);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004308
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004309 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004311 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 goto drop;
4313
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004314 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004315 case L2CAP_MODE_BASIC:
4316 /* If socket recv buffers overflows we drop data here
4317 * which is *bad* because L2CAP has to be reliable.
4318 * But we don't have any other choice. L2CAP doesn't
4319 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004321 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004322 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004324 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004325 goto done;
4326 break;
4327
4328 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004329 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004330
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004331 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004332
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004333 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004334 control = __get_control(chan, skb->data);
4335 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004336 len = skb->len;
4337
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004338 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004339 goto drop;
4340
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004341 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004342 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004343
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004344 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004345 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004346
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004347 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004348 goto drop;
4349
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004350 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004351
Mat Martineau84084a32011-07-22 14:54:00 -07004352 if (chan->expected_tx_seq != tx_seq) {
4353 /* Frame(s) missing - must discard partial SDU */
4354 kfree_skb(chan->sdu);
4355 chan->sdu = NULL;
4356 chan->sdu_last_frag = NULL;
4357 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004358
Mat Martineau84084a32011-07-22 14:54:00 -07004359 /* TODO: Notify userland of missing data */
4360 }
4361
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004362 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004363
4364 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4365 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004366
4367 goto done;
4368
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004369 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004370 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004371 break;
4372 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373
4374drop:
4375 kfree_skb(skb);
4376
4377done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004378 l2cap_chan_unlock(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +02004379
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 return 0;
4381}
4382
Al Viro8e036fc2007-07-29 00:16:36 -07004383static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004385 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004387 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4388 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 goto drop;
4390
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004391 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004393 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 goto drop;
4395
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004396 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 goto drop;
4398
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004399 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004400 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401
4402drop:
4403 kfree_skb(skb);
4404
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 return 0;
4406}
4407
Andrei Emeltchenkod9b88702012-03-12 12:13:08 +02004408static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
4409 struct sk_buff *skb)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004410{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004411 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004412
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004413 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4414 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004415 goto drop;
4416
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004417 BT_DBG("chan %p, len %d", chan, skb->len);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004418
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004419 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004420 goto drop;
4421
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004422 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004423 goto drop;
4424
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004425 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004426 return 0;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004427
4428drop:
4429 kfree_skb(skb);
4430
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004431 return 0;
4432}
4433
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4435{
4436 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004437 u16 cid, len;
4438 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439
4440 skb_pull(skb, L2CAP_HDR_SIZE);
4441 cid = __le16_to_cpu(lh->cid);
4442 len = __le16_to_cpu(lh->len);
4443
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004444 if (len != skb->len) {
4445 kfree_skb(skb);
4446 return;
4447 }
4448
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4450
4451 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004452 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004453 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 l2cap_sig_channel(conn, skb);
4455 break;
4456
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004457 case L2CAP_CID_CONN_LESS:
Andrei Emeltchenko097db762012-03-09 14:16:17 +02004458 psm = get_unaligned((__le16 *) skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 skb_pull(skb, 2);
4460 l2cap_conless_channel(conn, psm, skb);
4461 break;
4462
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004463 case L2CAP_CID_LE_DATA:
4464 l2cap_att_channel(conn, cid, skb);
4465 break;
4466
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004467 case L2CAP_CID_SMP:
4468 if (smp_sig_channel(conn, skb))
4469 l2cap_conn_del(conn->hcon, EACCES);
4470 break;
4471
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472 default:
4473 l2cap_data_channel(conn, cid, skb);
4474 break;
4475 }
4476}
4477
4478/* ---- L2CAP interface with lower layer (HCI) ---- */
4479
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004480int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481{
4482 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004483 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4486
4487 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004488 read_lock(&chan_list_lock);
4489 list_for_each_entry(c, &chan_list, global_l) {
4490 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004491
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004492 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 continue;
4494
4495 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004496 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004497 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004498 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004500 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4501 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004502 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004503 lm2 |= HCI_LM_MASTER;
4504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004506 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507
4508 return exact ? lm1 : lm2;
4509}
4510
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004511int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512{
Marcel Holtmann01394182006-07-03 10:02:46 +02004513 struct l2cap_conn *conn;
4514
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4516
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 conn = l2cap_conn_add(hcon, status);
4519 if (conn)
4520 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004521 } else
Joe Perchese1750722011-06-29 18:18:29 -07004522 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523
4524 return 0;
4525}
4526
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004527int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004528{
4529 struct l2cap_conn *conn = hcon->l2cap_data;
4530
4531 BT_DBG("hcon %p", hcon);
4532
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004533 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004534 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004535 return conn->disc_reason;
4536}
4537
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004538int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004539{
4540 BT_DBG("hcon %p reason %d", hcon, reason);
4541
Joe Perchese1750722011-06-29 18:18:29 -07004542 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 return 0;
4544}
4545
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004546static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004547{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004548 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004549 return;
4550
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004551 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004552 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004553 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004554 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004555 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004556 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004557 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004558 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004559 }
4560}
4561
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004562int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004564 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004565 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566
Marcel Holtmann01394182006-07-03 10:02:46 +02004567 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004569
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 BT_DBG("conn %p", conn);
4571
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004572 if (hcon->type == LE_LINK) {
4573 smp_distribute_keys(conn, 0);
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02004574 cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004575 }
4576
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004577 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004579 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004580 l2cap_chan_lock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004581
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004582 BT_DBG("chan->scid %d", chan->scid);
4583
4584 if (chan->scid == L2CAP_CID_LE_DATA) {
4585 if (!status && encrypt) {
4586 chan->sec_level = hcon->sec_level;
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02004587 l2cap_chan_ready(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004588 }
4589
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004590 l2cap_chan_unlock(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004591 continue;
4592 }
4593
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004594 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004595 l2cap_chan_unlock(chan);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004596 continue;
4597 }
4598
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004599 if (!status && (chan->state == BT_CONNECTED ||
4600 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004601 l2cap_check_encryption(chan, encrypt);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004602 l2cap_chan_unlock(chan);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004603 continue;
4604 }
4605
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004606 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004607 if (!status) {
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +02004608 l2cap_send_conn_req(chan);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004609 } else {
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004610 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004611 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004612 } else if (chan->state == BT_CONNECT2) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004613 struct sock *sk = chan->sk;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004614 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004615 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004616
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004617 lock_sock(sk);
4618
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004619 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004620 if (bt_sk(sk)->defer_setup) {
4621 struct sock *parent = bt_sk(sk)->parent;
4622 res = L2CAP_CR_PEND;
4623 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004624 if (parent)
4625 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004626 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004627 __l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004628 res = L2CAP_CR_SUCCESS;
4629 stat = L2CAP_CS_NO_INFO;
4630 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004631 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004632 __l2cap_state_change(chan, BT_DISCONN);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004633 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004634 res = L2CAP_CR_SEC_BLOCK;
4635 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004636 }
4637
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004638 release_sock(sk);
4639
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004640 rsp.scid = cpu_to_le16(chan->dcid);
4641 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004642 rsp.result = cpu_to_le16(res);
4643 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004644 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4645 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 }
4647
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004648 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 }
4650
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004651 mutex_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004652
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 return 0;
4654}
4655
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004656int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657{
4658 struct l2cap_conn *conn = hcon->l2cap_data;
4659
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004660 if (!conn)
4661 conn = l2cap_conn_add(hcon, 0);
4662
4663 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 goto drop;
4665
4666 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4667
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004668 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004670 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004671 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 int len;
4673
4674 if (conn->rx_len) {
4675 BT_ERR("Unexpected start frame (len %d)", skb->len);
4676 kfree_skb(conn->rx_skb);
4677 conn->rx_skb = NULL;
4678 conn->rx_len = 0;
4679 l2cap_conn_unreliable(conn, ECOMM);
4680 }
4681
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004682 /* Start fragment always begin with Basic L2CAP header */
4683 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 BT_ERR("Frame is too short (len %d)", skb->len);
4685 l2cap_conn_unreliable(conn, ECOMM);
4686 goto drop;
4687 }
4688
4689 hdr = (struct l2cap_hdr *) skb->data;
4690 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004691 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692
4693 if (len == skb->len) {
4694 /* Complete frame received */
4695 l2cap_recv_frame(conn, skb);
4696 return 0;
4697 }
4698
4699 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4700
4701 if (skb->len > len) {
4702 BT_ERR("Frame is too long (len %d, expected len %d)",
4703 skb->len, len);
4704 l2cap_conn_unreliable(conn, ECOMM);
4705 goto drop;
4706 }
4707
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004708 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004709
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004710 if (chan && chan->sk) {
4711 struct sock *sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004712 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004713
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004714 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004715 BT_ERR("Frame exceeding recv MTU (len %d, "
4716 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004717 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004718 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004719 l2cap_conn_unreliable(conn, ECOMM);
4720 goto drop;
4721 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004722 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004723 }
4724
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004726 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4727 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728 goto drop;
4729
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004730 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004731 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 conn->rx_len = len - skb->len;
4733 } else {
4734 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4735
4736 if (!conn->rx_len) {
4737 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4738 l2cap_conn_unreliable(conn, ECOMM);
4739 goto drop;
4740 }
4741
4742 if (skb->len > conn->rx_len) {
4743 BT_ERR("Fragment is too long (len %d, expected %d)",
4744 skb->len, conn->rx_len);
4745 kfree_skb(conn->rx_skb);
4746 conn->rx_skb = NULL;
4747 conn->rx_len = 0;
4748 l2cap_conn_unreliable(conn, ECOMM);
4749 goto drop;
4750 }
4751
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004752 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004753 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 conn->rx_len -= skb->len;
4755
4756 if (!conn->rx_len) {
4757 /* Complete frame received */
4758 l2cap_recv_frame(conn, conn->rx_skb);
4759 conn->rx_skb = NULL;
4760 }
4761 }
4762
4763drop:
4764 kfree_skb(skb);
4765 return 0;
4766}
4767
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004768static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004770 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004772 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004774 list_for_each_entry(c, &chan_list, global_l) {
4775 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004777 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 +01004778 batostr(&bt_sk(sk)->src),
4779 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004780 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004781 c->scid, c->dcid, c->imtu, c->omtu,
4782 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004783 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004785 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004786
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004787 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788}
4789
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004790static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4791{
4792 return single_open(file, l2cap_debugfs_show, inode->i_private);
4793}
4794
4795static const struct file_operations l2cap_debugfs_fops = {
4796 .open = l2cap_debugfs_open,
4797 .read = seq_read,
4798 .llseek = seq_lseek,
4799 .release = single_release,
4800};
4801
4802static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004804int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805{
4806 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004807
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004808 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 if (err < 0)
4810 return err;
4811
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004812 if (bt_debugfs) {
4813 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4814 bt_debugfs, NULL, &l2cap_debugfs_fops);
4815 if (!l2cap_debugfs)
4816 BT_ERR("Failed to create L2CAP debug file");
4817 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820}
4821
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004822void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004824 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004825 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826}
4827
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004828module_param(disable_ertm, bool, 0644);
4829MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");