blob: db04c9e4e1d93dc4c283b644f3ec30b77b09b9cb [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Gustavo F. Padovan590051d2011-12-18 13:39:33 -02006 Copyright (C) 2011 ProFUSION Embedded Systems
Linus Torvalds1da177e2005-04-16 15:20:36 -07007
8 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation;
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
17 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090023 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 SOFTWARE IS DISCLAIMED.
26*/
27
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020028/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31
32#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080033#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/errno.h>
35#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/sched.h>
37#include <linux/slab.h>
38#include <linux/poll.h>
39#include <linux/fcntl.h>
40#include <linux/init.h>
41#include <linux/interrupt.h>
42#include <linux/socket.h>
43#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080045#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010046#include <linux/debugfs.h>
47#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030048#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030049#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <net/sock.h>
51
52#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <asm/unaligned.h>
54
55#include <net/bluetooth/bluetooth.h>
56#include <net/bluetooth/hci_core.h>
57#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030058#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Rusty Russelleb939922011-12-19 14:08:01 +000060bool disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020061
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070062static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070063static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Johannes Bergb5ad8b72011-06-01 08:54:45 +020065static LIST_HEAD(chan_list);
66static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
69 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030070static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
71 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030072static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030073static void l2cap_send_disconn_req(struct l2cap_conn *conn,
74 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Marcel Holtmann01394182006-07-03 10:02:46 +020076/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030077
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030078static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020079{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020080 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030081
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020082 list_for_each_entry(c, &conn->chan_l, list) {
83 if (c->dcid == cid)
84 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020085 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020086 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020087}
88
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030089static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020090{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020091 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030092
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020093 list_for_each_entry(c, &conn->chan_l, list) {
94 if (c->scid == cid)
95 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020096 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020097 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020098}
99
100/* Find channel with given SCID.
101 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300102static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200103{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300104 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300105
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200106 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300107 c = __l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200108 mutex_unlock(&conn->chan_lock);
109
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300110 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200111}
112
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300113static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200114{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200115 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300116
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200117 list_for_each_entry(c, &conn->chan_l, list) {
118 if (c->ident == ident)
119 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200120 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200121 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200122}
123
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300124static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200125{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300126 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300127
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200128 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300129 c = __l2cap_get_chan_by_ident(conn, ident);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200130 mutex_unlock(&conn->chan_lock);
131
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300132 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200133}
134
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300135static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300136{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300137 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300138
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300139 list_for_each_entry(c, &chan_list, global_l) {
140 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100141 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300142 }
Szymon Janc250938c2011-11-16 09:32:22 +0100143 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300144}
145
146int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
147{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300148 int err;
149
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200150 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300151
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300152 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300153 err = -EADDRINUSE;
154 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300155 }
156
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300157 if (psm) {
158 chan->psm = psm;
159 chan->sport = psm;
160 err = 0;
161 } else {
162 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300163
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300164 err = -EINVAL;
165 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300166 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300167 chan->psm = cpu_to_le16(p);
168 chan->sport = cpu_to_le16(p);
169 err = 0;
170 break;
171 }
172 }
173
174done:
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200175 write_unlock(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300176 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300177}
178
179int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
180{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200181 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300182
183 chan->scid = scid;
184
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200185 write_unlock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300186
187 return 0;
188}
189
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300190static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200191{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300192 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200193
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300194 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300195 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200196 return cid;
197 }
198
199 return 0;
200}
201
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200202static void __l2cap_state_change(struct l2cap_chan *chan, int state)
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300203{
Andrei Emeltchenko42d2d872012-02-17 11:40:57 +0200204 BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200205 state_to_string(state));
206
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300207 chan->state = state;
208 chan->ops->state_change(chan->data, state);
209}
210
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200211static void l2cap_state_change(struct l2cap_chan *chan, int state)
212{
213 struct sock *sk = chan->sk;
214
215 lock_sock(sk);
216 __l2cap_state_change(chan, state);
217 release_sock(sk);
218}
219
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200220static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
221{
222 struct sock *sk = chan->sk;
223
224 sk->sk_err = err;
225}
226
227static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
228{
229 struct sock *sk = chan->sk;
230
231 lock_sock(sk);
232 __l2cap_chan_set_err(chan, err);
233 release_sock(sk);
234}
235
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300236static void l2cap_chan_timeout(struct work_struct *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300237{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300238 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
239 chan_timer.work);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200240 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300241 int reason;
242
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200243 BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300244
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200245 mutex_lock(&conn->chan_lock);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200246 l2cap_chan_lock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300247
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300248 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300249 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300250 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300251 chan->sec_level != BT_SECURITY_SDP)
252 reason = ECONNREFUSED;
253 else
254 reason = ETIMEDOUT;
255
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300256 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300257
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200258 l2cap_chan_unlock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300259
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300260 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200261 mutex_unlock(&conn->chan_lock);
262
Ulisses Furquim371fd832011-12-21 20:02:36 -0200263 l2cap_chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300264}
265
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300266struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200267{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300268 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200269
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300270 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
271 if (!chan)
272 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200273
Andrei Emeltchenkoc03b3552012-02-21 12:54:56 +0200274 mutex_init(&chan->lock);
275
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300276 chan->sk = sk;
277
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200278 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300279 list_add(&chan->global_l, &chan_list);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200280 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300281
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300282 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300283
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300284 chan->state = BT_OPEN;
285
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300286 atomic_set(&chan->refcnt, 1);
287
Szymon Jancabc545b2011-11-03 16:05:44 +0100288 BT_DBG("sk %p chan %p", sk, chan);
289
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300290 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200291}
292
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300293void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300294{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200295 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300296 list_del(&chan->global_l);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200297 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300298
Ulisses Furquim371fd832011-12-21 20:02:36 -0200299 l2cap_chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300300}
301
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200302void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200303{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300304 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300305 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200306
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200307 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100308
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300309 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200310
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200311 switch (chan->chan_type) {
312 case L2CAP_CHAN_CONN_ORIENTED:
Ville Tervob62f3282011-02-10 22:38:50 -0300313 if (conn->hcon->type == LE_LINK) {
314 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300315 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300316 chan->scid = L2CAP_CID_LE_DATA;
317 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300318 } else {
319 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300320 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300321 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300322 }
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200323 break;
324
325 case L2CAP_CHAN_CONN_LESS:
Marcel Holtmann01394182006-07-03 10:02:46 +0200326 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300327 chan->scid = L2CAP_CID_CONN_LESS;
328 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300329 chan->omtu = L2CAP_DEFAULT_MTU;
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200330 break;
331
332 default:
Marcel Holtmann01394182006-07-03 10:02:46 +0200333 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300334 chan->scid = L2CAP_CID_SIGNALING;
335 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300336 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200337 }
338
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300339 chan->local_id = L2CAP_BESTEFFORT_ID;
340 chan->local_stype = L2CAP_SERV_BESTEFFORT;
341 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
342 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
343 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
344 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
345
Ulisses Furquim371fd832011-12-21 20:02:36 -0200346 l2cap_chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300347
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200348 list_add(&chan->list, &conn->chan_l);
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200349}
350
351void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
352{
353 mutex_lock(&conn->chan_lock);
354 __l2cap_chan_add(conn, chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200355 mutex_unlock(&conn->chan_lock);
Marcel Holtmann01394182006-07-03 10:02:46 +0200356}
357
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300358static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200359{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300360 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300361 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200362 struct sock *parent = bt_sk(sk)->parent;
363
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300364 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200365
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300366 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200367
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900368 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300369 /* Delete from channel list */
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200370 list_del(&chan->list);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200371
Ulisses Furquim371fd832011-12-21 20:02:36 -0200372 l2cap_chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300373
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300374 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200375 hci_conn_put(conn->hcon);
376 }
377
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200378 lock_sock(sk);
379
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200380 __l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200381 sock_set_flag(sk, SOCK_ZAPPED);
382
383 if (err)
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200384 __l2cap_chan_set_err(chan, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200385
386 if (parent) {
387 bt_accept_unlink(sk);
388 parent->sk_data_ready(parent, 0);
389 } else
390 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300391
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200392 release_sock(sk);
393
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300394 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
395 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300396 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300397
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300398 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300399
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300400 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300401 struct srej_list *l, *tmp;
402
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300403 __clear_retrans_timer(chan);
404 __clear_monitor_timer(chan);
405 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300406
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300407 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300408
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300409 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300410 list_del(&l->list);
411 kfree(l);
412 }
413 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200414}
415
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300416static void l2cap_chan_cleanup_listen(struct sock *parent)
417{
418 struct sock *sk;
419
420 BT_DBG("parent %p", parent);
421
422 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300423 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300424 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200425
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200426 l2cap_chan_lock(chan);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300427 __clear_chan_timer(chan);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300428 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200429 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200430
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300431 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300432 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300433}
434
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300435void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300436{
437 struct l2cap_conn *conn = chan->conn;
438 struct sock *sk = chan->sk;
439
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200440 BT_DBG("chan %p state %s sk %p", chan,
441 state_to_string(chan->state), sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300442
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300443 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300444 case BT_LISTEN:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200445 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300446 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300447
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200448 __l2cap_state_change(chan, BT_CLOSED);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300449 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200450 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300451 break;
452
453 case BT_CONNECTED:
454 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300455 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300456 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300457 __clear_chan_timer(chan);
458 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300459 l2cap_send_disconn_req(conn, chan, reason);
460 } else
461 l2cap_chan_del(chan, reason);
462 break;
463
464 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300465 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300466 conn->hcon->type == ACL_LINK) {
467 struct l2cap_conn_rsp rsp;
468 __u16 result;
469
470 if (bt_sk(sk)->defer_setup)
471 result = L2CAP_CR_SEC_BLOCK;
472 else
473 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300474 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300475
476 rsp.scid = cpu_to_le16(chan->dcid);
477 rsp.dcid = cpu_to_le16(chan->scid);
478 rsp.result = cpu_to_le16(result);
479 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
480 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
481 sizeof(rsp), &rsp);
482 }
483
484 l2cap_chan_del(chan, reason);
485 break;
486
487 case BT_CONNECT:
488 case BT_DISCONN:
489 l2cap_chan_del(chan, reason);
490 break;
491
492 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200493 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300494 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200495 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300496 break;
497 }
498}
499
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300500static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530501{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300502 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300503 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530504 case BT_SECURITY_HIGH:
505 return HCI_AT_DEDICATED_BONDING_MITM;
506 case BT_SECURITY_MEDIUM:
507 return HCI_AT_DEDICATED_BONDING;
508 default:
509 return HCI_AT_NO_BONDING;
510 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300511 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300512 if (chan->sec_level == BT_SECURITY_LOW)
513 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530514
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300515 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530516 return HCI_AT_NO_BONDING_MITM;
517 else
518 return HCI_AT_NO_BONDING;
519 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300520 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530521 case BT_SECURITY_HIGH:
522 return HCI_AT_GENERAL_BONDING_MITM;
523 case BT_SECURITY_MEDIUM:
524 return HCI_AT_GENERAL_BONDING;
525 default:
526 return HCI_AT_NO_BONDING;
527 }
528 }
529}
530
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200531/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200532int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200533{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300534 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100535 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200536
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300537 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100538
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300539 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200540}
541
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200542static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200543{
544 u8 id;
545
546 /* Get next available identificator.
547 * 1 - 128 are used by kernel.
548 * 129 - 199 are reserved.
549 * 200 - 254 are used by utilities like l2ping, etc.
550 */
551
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200552 spin_lock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200553
554 if (++conn->tx_ident > 128)
555 conn->tx_ident = 1;
556
557 id = conn->tx_ident;
558
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200559 spin_unlock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200560
561 return id;
562}
563
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300564static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200565{
566 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200567 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200568
569 BT_DBG("code 0x%2.2x", code);
570
571 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300572 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200573
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200574 if (lmp_no_flush_capable(conn->hcon->hdev))
575 flags = ACL_START_NO_FLUSH;
576 else
577 flags = ACL_START;
578
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700579 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200580 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700581
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200582 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200583}
584
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200585static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
586{
587 struct hci_conn *hcon = chan->conn->hcon;
588 u16 flags;
589
590 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
591 skb->priority);
592
593 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
594 lmp_no_flush_capable(hcon->hdev))
595 flags = ACL_START_NO_FLUSH;
596 else
597 flags = ACL_START;
598
599 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
600 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300603static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300604{
605 struct sk_buff *skb;
606 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300607 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300608 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300609
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300610 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300611 return;
612
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300613 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
614 hlen = L2CAP_EXT_HDR_SIZE;
615 else
616 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300617
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300618 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300619 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300620
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300621 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300622
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300623 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300624
625 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300626
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300627 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300628 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300629
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300630 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300631 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300632
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300633 skb = bt_skb_alloc(count, GFP_ATOMIC);
634 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300635 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300636
637 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300638 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300639 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300640
641 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300642
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300643 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300644 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
645 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300646 }
647
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200648 skb->priority = HCI_PRIO_MAX;
649 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300650}
651
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300652static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300653{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300654 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300655 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300656 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300657 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300658 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300659
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300660 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300661
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300662 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300663}
664
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300665static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300666{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300667 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300668}
669
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300670static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200671{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300672 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200673
674 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100675 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
676 return;
677
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200678 if (l2cap_chan_check_security(chan) &&
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300679 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200680 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300681 req.scid = cpu_to_le16(chan->scid);
682 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200683
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300684 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300685 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200686
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300687 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
688 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200689 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200690 } else {
691 struct l2cap_info_req req;
692 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
693
694 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
695 conn->info_ident = l2cap_get_ident(conn);
696
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200697 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200698 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
699
700 l2cap_send_cmd(conn, conn->info_ident,
701 L2CAP_INFO_REQ, sizeof(req), &req);
702 }
703}
704
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300705static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
706{
707 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300708 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300709 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
710
711 switch (mode) {
712 case L2CAP_MODE_ERTM:
713 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
714 case L2CAP_MODE_STREAMING:
715 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
716 default:
717 return 0x00;
718 }
719}
720
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300721static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300722{
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200723 struct sock *sk = chan->sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300724 struct l2cap_disconn_req req;
725
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300726 if (!conn)
727 return;
728
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300729 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300730 __clear_retrans_timer(chan);
731 __clear_monitor_timer(chan);
732 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300733 }
734
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300735 req.dcid = cpu_to_le16(chan->dcid);
736 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300737 l2cap_send_cmd(conn, l2cap_get_ident(conn),
738 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300739
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200740 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200741 __l2cap_state_change(chan, BT_DISCONN);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200742 __l2cap_chan_set_err(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200743 release_sock(sk);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300744}
745
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200747static void l2cap_conn_start(struct l2cap_conn *conn)
748{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200749 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200750
751 BT_DBG("conn %p", conn);
752
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200753 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200754
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200755 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300756 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300757
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200758 l2cap_chan_lock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200759
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300760 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200761 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200762 continue;
763 }
764
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300765 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300766 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300767
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200768 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300769 !__l2cap_no_conn_pending(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200770 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300771 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200772 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300773
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300774 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
775 && test_bit(CONF_STATE2_DEVICE,
776 &chan->conf_state)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300777 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200778 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300779 continue;
780 }
781
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300782 req.scid = cpu_to_le16(chan->scid);
783 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300784
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300785 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300786 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300787
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300788 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
789 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300790
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300791 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200792 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300793 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300794 rsp.scid = cpu_to_le16(chan->dcid);
795 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200796
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200797 if (l2cap_chan_check_security(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200798 lock_sock(sk);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100799 if (bt_sk(sk)->defer_setup) {
800 struct sock *parent = bt_sk(sk)->parent;
801 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
802 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000803 if (parent)
804 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100805
806 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200807 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100808 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
809 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
810 }
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200811 release_sock(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200812 } else {
813 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
814 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
815 }
816
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300817 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
818 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300819
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300820 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300821 rsp.result != L2CAP_CR_SUCCESS) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200822 l2cap_chan_unlock(chan);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300823 continue;
824 }
825
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300826 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300827 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300828 l2cap_build_conf_req(chan, buf), buf);
829 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200830 }
831
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200832 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200833 }
834
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200835 mutex_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200836}
837
Ville Tervob62f3282011-02-10 22:38:50 -0300838/* Find socket with cid and source bdaddr.
839 * Returns closest match, locked.
840 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300841static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300842{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300843 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300844
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300845 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300846
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300847 list_for_each_entry(c, &chan_list, global_l) {
848 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300849
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300850 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300851 continue;
852
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300853 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300854 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300855 if (!bacmp(&bt_sk(sk)->src, src)) {
856 read_unlock(&chan_list_lock);
857 return c;
858 }
Ville Tervob62f3282011-02-10 22:38:50 -0300859
860 /* Closest match */
861 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300862 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300863 }
864 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300865
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300866 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300867
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300868 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300869}
870
871static void l2cap_le_conn_ready(struct l2cap_conn *conn)
872{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300873 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300874 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300875
876 BT_DBG("");
877
878 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300879 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300880 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300881 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300882 return;
883
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300884 parent = pchan->sk;
885
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300886 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300887
Ville Tervob62f3282011-02-10 22:38:50 -0300888 /* Check for backlog size */
889 if (sk_acceptq_is_full(parent)) {
890 BT_DBG("backlog full %d", parent->sk_ack_backlog);
891 goto clean;
892 }
893
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300894 chan = pchan->ops->new_connection(pchan->data);
895 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300896 goto clean;
897
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300898 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300899
Ville Tervob62f3282011-02-10 22:38:50 -0300900 hci_conn_hold(conn->hcon);
901
Ville Tervob62f3282011-02-10 22:38:50 -0300902 bacpy(&bt_sk(sk)->src, conn->src);
903 bacpy(&bt_sk(sk)->dst, conn->dst);
904
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300905 bt_accept_enqueue(parent, sk);
906
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200907 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300908
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300909 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300910
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200911 __l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300912 parent->sk_data_ready(parent, 0);
913
Ville Tervob62f3282011-02-10 22:38:50 -0300914clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300915 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300916}
917
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200918static void l2cap_chan_ready(struct l2cap_chan *chan)
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300919{
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200920 struct sock *sk = chan->sk;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200921 struct sock *parent;
922
923 lock_sock(sk);
924
925 parent = bt_sk(sk)->parent;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300926
927 BT_DBG("sk %p, parent %p", sk, parent);
928
929 chan->conf_state = 0;
930 __clear_chan_timer(chan);
931
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200932 __l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300933 sk->sk_state_change(sk);
934
935 if (parent)
936 parent->sk_data_ready(parent, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200937
938 release_sock(sk);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300939}
940
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200941static void l2cap_conn_ready(struct l2cap_conn *conn)
942{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300943 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200944
945 BT_DBG("conn %p", conn);
946
Ville Tervob62f3282011-02-10 22:38:50 -0300947 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
948 l2cap_le_conn_ready(conn);
949
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300950 if (conn->hcon->out && conn->hcon->type == LE_LINK)
951 smp_conn_security(conn, conn->hcon->pending_sec_level);
952
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200953 mutex_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200954
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200955 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300956
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200957 l2cap_chan_lock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200958
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300959 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300960 if (smp_conn_security(conn, chan->sec_level))
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200961 l2cap_chan_ready(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300962
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300963 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200964 struct sock *sk = chan->sk;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300965 __clear_chan_timer(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200966 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200967 __l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200968 sk->sk_state_change(sk);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200969 release_sock(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300970
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300971 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300972 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200973
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200974 l2cap_chan_unlock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200975 }
976
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200977 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200978}
979
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200980/* Notify sockets that we cannot guaranty reliability anymore */
981static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
982{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300983 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200984
985 BT_DBG("conn %p", conn);
986
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200987 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200988
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200989 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300990 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200991 __l2cap_chan_set_err(chan, err);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200992 }
993
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200994 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200995}
996
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200997static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200998{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200999 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001000 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001001
Marcel Holtmann984947d2009-02-06 23:35:19 +01001002 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01001003 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01001004
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001005 l2cap_conn_start(conn);
1006}
1007
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001008static void l2cap_conn_del(struct hci_conn *hcon, int err)
1009{
1010 struct l2cap_conn *conn = hcon->l2cap_data;
1011 struct l2cap_chan *chan, *l;
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001012
1013 if (!conn)
1014 return;
1015
1016 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1017
1018 kfree_skb(conn->rx_skb);
1019
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001020 mutex_lock(&conn->chan_lock);
1021
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001022 /* Kill channels */
1023 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001024 l2cap_chan_lock(chan);
1025
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001026 l2cap_chan_del(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001027
1028 l2cap_chan_unlock(chan);
1029
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001030 chan->ops->close(chan->data);
1031 }
1032
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001033 mutex_unlock(&conn->chan_lock);
1034
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001035 hci_chan_del(conn->hchan);
1036
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001037 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim127074b2012-01-30 18:26:29 -02001038 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001039
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001040 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim127074b2012-01-30 18:26:29 -02001041 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001042 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001043 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001044
1045 hcon->l2cap_data = NULL;
1046 kfree(conn);
1047}
1048
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001049static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001050{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001051 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1052 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001053
1054 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1055}
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1058{
Marcel Holtmann01394182006-07-03 10:02:46 +02001059 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001060 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Marcel Holtmann01394182006-07-03 10:02:46 +02001062 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 return conn;
1064
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001065 hchan = hci_chan_create(hcon);
1066 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001069 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1070 if (!conn) {
1071 hci_chan_del(hchan);
1072 return NULL;
1073 }
1074
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 hcon->l2cap_data = conn;
1076 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001077 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001079 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001080
Ville Tervoacd7d372011-02-10 22:38:49 -03001081 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1082 conn->mtu = hcon->hdev->le_mtu;
1083 else
1084 conn->mtu = hcon->hdev->acl_mtu;
1085
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 conn->src = &hcon->hdev->bdaddr;
1087 conn->dst = &hcon->dst;
1088
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001089 conn->feat_mask = 0;
1090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 spin_lock_init(&conn->lock);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001092 mutex_init(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001093
1094 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001096 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001097 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001098 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001099 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001100
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001101 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001102
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 return conn;
1104}
1105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
1108/* Find socket with psm and source bdaddr.
1109 * Returns closest match.
1110 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001111static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001113 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001115 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001116
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001117 list_for_each_entry(c, &chan_list, global_l) {
1118 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001119
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001120 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 continue;
1122
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001123 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001125 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001126 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001127 return c;
1128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130 /* Closest match */
1131 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001132 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 }
1134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001136 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001137
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001138 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139}
1140
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001141int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001143 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 struct l2cap_conn *conn;
1146 struct hci_conn *hcon;
1147 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001148 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001149 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001151 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001152 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001154 hdev = hci_get_route(dst, src);
1155 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 return -EHOSTUNREACH;
1157
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001158 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001160 l2cap_chan_lock(chan);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001161
1162 /* PSM must be odd and lsb of upper byte must be 0 */
1163 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1164 chan->chan_type != L2CAP_CHAN_RAW) {
1165 err = -EINVAL;
1166 goto done;
1167 }
1168
1169 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1170 err = -EINVAL;
1171 goto done;
1172 }
1173
1174 switch (chan->mode) {
1175 case L2CAP_MODE_BASIC:
1176 break;
1177 case L2CAP_MODE_ERTM:
1178 case L2CAP_MODE_STREAMING:
1179 if (!disable_ertm)
1180 break;
1181 /* fall through */
1182 default:
1183 err = -ENOTSUPP;
1184 goto done;
1185 }
1186
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001187 lock_sock(sk);
1188
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001189 switch (sk->sk_state) {
1190 case BT_CONNECT:
1191 case BT_CONNECT2:
1192 case BT_CONFIG:
1193 /* Already connecting */
1194 err = 0;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001195 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001196 goto done;
1197
1198 case BT_CONNECTED:
1199 /* Already connected */
1200 err = -EISCONN;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001201 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001202 goto done;
1203
1204 case BT_OPEN:
1205 case BT_BOUND:
1206 /* Can connect */
1207 break;
1208
1209 default:
1210 err = -EBADFD;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001211 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001212 goto done;
1213 }
1214
1215 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001216 bacpy(&bt_sk(sk)->dst, dst);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001217
1218 release_sock(sk);
1219
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001220 chan->psm = psm;
1221 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001223 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001224
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001225 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001226 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001227 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001228 else
1229 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001230 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001231
Ville Tervo30e76272011-02-22 16:10:53 -03001232 if (IS_ERR(hcon)) {
1233 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001235 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237 conn = l2cap_conn_add(hcon, 0);
1238 if (!conn) {
1239 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001240 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 goto done;
1242 }
1243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 /* Update source addr of the socket */
1245 bacpy(src, conn->src);
1246
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001247 l2cap_chan_unlock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001248 l2cap_chan_add(conn, chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001249 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001250
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001251 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001252 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001255 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001256 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001257 if (l2cap_chan_check_security(chan))
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001258 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001259 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001260 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 }
1262
Ville Tervo30e76272011-02-22 16:10:53 -03001263 err = 0;
1264
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001266 l2cap_chan_unlock(chan);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001267 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 hci_dev_put(hdev);
1269 return err;
1270}
1271
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001272int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001273{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001274 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001275 DECLARE_WAITQUEUE(wait, current);
1276 int err = 0;
1277 int timeo = HZ/5;
1278
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001279 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001280 set_current_state(TASK_INTERRUPTIBLE);
1281 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001282 if (!timeo)
1283 timeo = HZ/5;
1284
1285 if (signal_pending(current)) {
1286 err = sock_intr_errno(timeo);
1287 break;
1288 }
1289
1290 release_sock(sk);
1291 timeo = schedule_timeout(timeo);
1292 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001293 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001294
1295 err = sock_error(sk);
1296 if (err)
1297 break;
1298 }
1299 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001300 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001301 return err;
1302}
1303
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001304static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001305{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001306 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1307 monitor_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001308
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001309 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001310
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001311 l2cap_chan_lock(chan);
1312
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001313 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001314 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001315 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001316 return;
1317 }
1318
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001319 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001320 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001321
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001322 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001323 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001324}
1325
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001326static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001327{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001328 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1329 retrans_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001330
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001331 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001332
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001333 l2cap_chan_lock(chan);
1334
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001335 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001336 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001337
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001338 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001339
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001340 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001341
1342 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001343}
1344
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001345static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001346{
1347 struct sk_buff *skb;
1348
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001349 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001350 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001351 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001352 break;
1353
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001354 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001355 kfree_skb(skb);
1356
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001357 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001358 }
1359
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001360 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001361 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001362}
1363
Szymon Janc67c9e842011-07-28 16:24:33 +02001364static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001365{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001366 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001367 u32 control;
1368 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001369
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001370 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001371 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001372 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001373 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001374
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001375 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001376 fcs = crc16(0, (u8 *)skb->data,
1377 skb->len - L2CAP_FCS_SIZE);
1378 put_unaligned_le16(fcs,
1379 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001380 }
1381
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001382 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001383
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001384 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001385 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001386}
1387
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001388static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001389{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001390 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001391 u16 fcs;
1392 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001393
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001394 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001395 if (!skb)
1396 return;
1397
Szymon Jancd1726b62011-11-16 09:32:20 +01001398 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001399 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001400 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001401
Szymon Jancd1726b62011-11-16 09:32:20 +01001402 skb = skb_queue_next(&chan->tx_q, skb);
1403 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001404
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001405 if (chan->remote_max_tx &&
1406 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001407 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001408 return;
1409 }
1410
1411 tx_skb = skb_clone(skb, GFP_ATOMIC);
1412 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001413
1414 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001415 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001416
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001417 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001418 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001419
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001420 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001421 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001422
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001423 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001424
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001425 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001426 fcs = crc16(0, (u8 *)tx_skb->data,
1427 tx_skb->len - L2CAP_FCS_SIZE);
1428 put_unaligned_le16(fcs,
1429 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001430 }
1431
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001432 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001433}
1434
Szymon Janc67c9e842011-07-28 16:24:33 +02001435static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001436{
1437 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001438 u16 fcs;
1439 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001440 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001441
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001442 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001443 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001444
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001445 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001446
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001447 if (chan->remote_max_tx &&
1448 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001449 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001450 break;
1451 }
1452
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001453 tx_skb = skb_clone(skb, GFP_ATOMIC);
1454
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001455 bt_cb(skb)->retries++;
1456
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001457 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001458 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001459
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001460 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001461 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001462
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001463 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001464 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001465
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001466 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001467
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001468 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001469 fcs = crc16(0, (u8 *)skb->data,
1470 tx_skb->len - L2CAP_FCS_SIZE);
1471 put_unaligned_le16(fcs, skb->data +
1472 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001473 }
1474
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001475 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001476
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001477 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001478
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001479 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001480
1481 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001482
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001483 if (bt_cb(skb)->retries == 1) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001484 chan->unacked_frames++;
Szymon Janc930fa4a2012-02-07 15:43:02 +01001485
1486 if (!nsent++)
1487 __clear_ack_timer(chan);
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001488 }
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301489
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001490 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001491
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001492 if (skb_queue_is_last(&chan->tx_q, skb))
1493 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001494 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001495 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001496 }
1497
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001498 return nsent;
1499}
1500
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001501static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001502{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001503 int ret;
1504
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001505 if (!skb_queue_empty(&chan->tx_q))
1506 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001507
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001508 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001509 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001510 return ret;
1511}
1512
Szymon Jancb17e73b2012-01-11 10:59:47 +01001513static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001514{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001515 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001516
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001517 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001518
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001519 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001520 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001521 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001522 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001523 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001524 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001525
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001526 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001527 return;
1528
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001529 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001530 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001531}
1532
Szymon Jancb17e73b2012-01-11 10:59:47 +01001533static void l2cap_send_ack(struct l2cap_chan *chan)
1534{
1535 __clear_ack_timer(chan);
1536 __l2cap_send_ack(chan);
1537}
1538
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001539static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001540{
1541 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001542 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001543
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001544 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001545 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001546
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001547 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001548 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001549
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001550 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001551}
1552
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001553static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr *msg, int len, int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001555 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001556 struct sk_buff **frag;
1557 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001559 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001560 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562 sent += count;
1563 len -= count;
1564
1565 /* Continuation fragments (no L2CAP header) */
1566 frag = &skb_shinfo(skb)->frag_list;
1567 while (len) {
1568 count = min_t(unsigned int, conn->mtu, len);
1569
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001570 *frag = chan->ops->alloc_skb(chan, count,
1571 msg->msg_flags & MSG_DONTWAIT, &err);
1572
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001574 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001575 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1576 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001578 (*frag)->priority = skb->priority;
1579
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 sent += count;
1581 len -= count;
1582
1583 frag = &(*frag)->next;
1584 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585
1586 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001587}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001589static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1590 struct msghdr *msg, size_t len,
1591 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001592{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001593 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001594 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001595 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001596 struct l2cap_hdr *lh;
1597
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001598 BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001599
1600 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001601
1602 skb = chan->ops->alloc_skb(chan, count + hlen,
1603 msg->msg_flags & MSG_DONTWAIT, &err);
1604
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001605 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001606 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001607
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001608 skb->priority = priority;
1609
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001610 /* Create L2CAP header */
1611 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001612 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001613 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001614 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001615
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001616 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001617 if (unlikely(err < 0)) {
1618 kfree_skb(skb);
1619 return ERR_PTR(err);
1620 }
1621 return skb;
1622}
1623
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001624static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1625 struct msghdr *msg, size_t len,
1626 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001627{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001628 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001629 struct sk_buff *skb;
1630 int err, count, hlen = L2CAP_HDR_SIZE;
1631 struct l2cap_hdr *lh;
1632
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001633 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001634
1635 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001636
1637 skb = chan->ops->alloc_skb(chan, count + hlen,
1638 msg->msg_flags & MSG_DONTWAIT, &err);
1639
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001640 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001641 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001642
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001643 skb->priority = priority;
1644
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001645 /* Create L2CAP header */
1646 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001647 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001648 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1649
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001650 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001651 if (unlikely(err < 0)) {
1652 kfree_skb(skb);
1653 return ERR_PTR(err);
1654 }
1655 return skb;
1656}
1657
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001658static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1659 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001660 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001661{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001662 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001663 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001664 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001665 struct l2cap_hdr *lh;
1666
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001667 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001668
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001669 if (!conn)
1670 return ERR_PTR(-ENOTCONN);
1671
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001672 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1673 hlen = L2CAP_EXT_HDR_SIZE;
1674 else
1675 hlen = L2CAP_ENH_HDR_SIZE;
1676
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001677 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001678 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001679
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001680 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001681 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001682
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001683 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001684
1685 skb = chan->ops->alloc_skb(chan, count + hlen,
1686 msg->msg_flags & MSG_DONTWAIT, &err);
1687
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001688 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001689 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001690
1691 /* Create L2CAP header */
1692 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001693 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001694 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001695
1696 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1697
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001698 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001699 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001700
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001701 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001702 if (unlikely(err < 0)) {
1703 kfree_skb(skb);
1704 return ERR_PTR(err);
1705 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001706
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001707 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001708 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001709
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001710 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001711 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712}
1713
Szymon Janc67c9e842011-07-28 16:24:33 +02001714static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001715{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001716 struct sk_buff *skb;
1717 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001718 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001719 size_t size = 0;
1720
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001721 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001722 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001723 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001724 if (IS_ERR(skb))
1725 return PTR_ERR(skb);
1726
1727 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001728 len -= chan->remote_mps;
1729 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001730
1731 while (len > 0) {
1732 size_t buflen;
1733
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001734 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001735 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001736 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001737 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001738 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001739 buflen = len;
1740 }
1741
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001742 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001743 if (IS_ERR(skb)) {
1744 skb_queue_purge(&sar_queue);
1745 return PTR_ERR(skb);
1746 }
1747
1748 __skb_queue_tail(&sar_queue, skb);
1749 len -= buflen;
1750 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001751 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001752 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1753 if (chan->tx_send_head == NULL)
1754 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001755
1756 return size;
1757}
1758
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001759int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1760 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001761{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001762 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001763 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001764 int err;
1765
1766 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001767 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001768 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001769 if (IS_ERR(skb))
1770 return PTR_ERR(skb);
1771
1772 l2cap_do_send(chan, skb);
1773 return len;
1774 }
1775
1776 switch (chan->mode) {
1777 case L2CAP_MODE_BASIC:
1778 /* Check outgoing MTU */
1779 if (len > chan->omtu)
1780 return -EMSGSIZE;
1781
1782 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001783 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001784 if (IS_ERR(skb))
1785 return PTR_ERR(skb);
1786
1787 l2cap_do_send(chan, skb);
1788 err = len;
1789 break;
1790
1791 case L2CAP_MODE_ERTM:
1792 case L2CAP_MODE_STREAMING:
1793 /* Entire SDU fits into one PDU */
1794 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001795 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001796 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1797 0);
1798 if (IS_ERR(skb))
1799 return PTR_ERR(skb);
1800
1801 __skb_queue_tail(&chan->tx_q, skb);
1802
1803 if (chan->tx_send_head == NULL)
1804 chan->tx_send_head = skb;
1805
1806 } else {
1807 /* Segment SDU into multiples PDUs */
1808 err = l2cap_sar_segment_sdu(chan, msg, len);
1809 if (err < 0)
1810 return err;
1811 }
1812
1813 if (chan->mode == L2CAP_MODE_STREAMING) {
1814 l2cap_streaming_send(chan);
1815 err = len;
1816 break;
1817 }
1818
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001819 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1820 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001821 err = len;
1822 break;
1823 }
1824
1825 err = l2cap_ertm_send(chan);
1826 if (err >= 0)
1827 err = len;
1828
1829 break;
1830
1831 default:
1832 BT_DBG("bad state %1.1x", chan->mode);
1833 err = -EBADFD;
1834 }
1835
1836 return err;
1837}
1838
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839/* Copy frame to all raw sockets on that connection */
1840static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1841{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001843 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844
1845 BT_DBG("conn %p", conn);
1846
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001847 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001848
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001849 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001850 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001851 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 continue;
1853
1854 /* Don't send frame to the socket it came from */
1855 if (skb->sk == sk)
1856 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001857 nskb = skb_clone(skb, GFP_ATOMIC);
1858 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 continue;
1860
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001861 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 kfree_skb(nskb);
1863 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001864
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001865 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866}
1867
1868/* ---- L2CAP signalling commands ---- */
1869static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1870 u8 code, u8 ident, u16 dlen, void *data)
1871{
1872 struct sk_buff *skb, **frag;
1873 struct l2cap_cmd_hdr *cmd;
1874 struct l2cap_hdr *lh;
1875 int len, count;
1876
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001877 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1878 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879
1880 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1881 count = min_t(unsigned int, conn->mtu, len);
1882
1883 skb = bt_skb_alloc(count, GFP_ATOMIC);
1884 if (!skb)
1885 return NULL;
1886
1887 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001888 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001889
1890 if (conn->hcon->type == LE_LINK)
1891 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1892 else
1893 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894
1895 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1896 cmd->code = code;
1897 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001898 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899
1900 if (dlen) {
1901 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1902 memcpy(skb_put(skb, count), data, count);
1903 data += count;
1904 }
1905
1906 len -= skb->len;
1907
1908 /* Continuation fragments (no L2CAP header) */
1909 frag = &skb_shinfo(skb)->frag_list;
1910 while (len) {
1911 count = min_t(unsigned int, conn->mtu, len);
1912
1913 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1914 if (!*frag)
1915 goto fail;
1916
1917 memcpy(skb_put(*frag, count), data, count);
1918
1919 len -= count;
1920 data += count;
1921
1922 frag = &(*frag)->next;
1923 }
1924
1925 return skb;
1926
1927fail:
1928 kfree_skb(skb);
1929 return NULL;
1930}
1931
1932static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1933{
1934 struct l2cap_conf_opt *opt = *ptr;
1935 int len;
1936
1937 len = L2CAP_CONF_OPT_SIZE + opt->len;
1938 *ptr += len;
1939
1940 *type = opt->type;
1941 *olen = opt->len;
1942
1943 switch (opt->len) {
1944 case 1:
1945 *val = *((u8 *) opt->val);
1946 break;
1947
1948 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001949 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 break;
1951
1952 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001953 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 break;
1955
1956 default:
1957 *val = (unsigned long) opt->val;
1958 break;
1959 }
1960
1961 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1962 return len;
1963}
1964
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1966{
1967 struct l2cap_conf_opt *opt = *ptr;
1968
1969 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1970
1971 opt->type = type;
1972 opt->len = len;
1973
1974 switch (len) {
1975 case 1:
1976 *((u8 *) opt->val) = val;
1977 break;
1978
1979 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001980 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 break;
1982
1983 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001984 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 break;
1986
1987 default:
1988 memcpy(opt->val, (void *) val, len);
1989 break;
1990 }
1991
1992 *ptr += L2CAP_CONF_OPT_SIZE + len;
1993}
1994
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001995static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1996{
1997 struct l2cap_conf_efs efs;
1998
Szymon Janc1ec918c2011-11-16 09:32:21 +01001999 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002000 case L2CAP_MODE_ERTM:
2001 efs.id = chan->local_id;
2002 efs.stype = chan->local_stype;
2003 efs.msdu = cpu_to_le16(chan->local_msdu);
2004 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2005 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
2006 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
2007 break;
2008
2009 case L2CAP_MODE_STREAMING:
2010 efs.id = 1;
2011 efs.stype = L2CAP_SERV_BESTEFFORT;
2012 efs.msdu = cpu_to_le16(chan->local_msdu);
2013 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2014 efs.acc_lat = 0;
2015 efs.flush_to = 0;
2016 break;
2017
2018 default:
2019 return;
2020 }
2021
2022 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
2023 (unsigned long) &efs);
2024}
2025
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002026static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002027{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002028 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2029 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002030
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02002031 BT_DBG("chan %p", chan);
2032
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002033 l2cap_chan_lock(chan);
2034
Szymon Jancb17e73b2012-01-11 10:59:47 +01002035 __l2cap_send_ack(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002036
2037 l2cap_chan_unlock(chan);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002038
2039 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002040}
2041
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002042static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002043{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002044 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002045 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002046 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002047 chan->num_acked = 0;
2048 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002049
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002050 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2051 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2052 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002053
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002054 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002055
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002056 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002057}
2058
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002059static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2060{
2061 switch (mode) {
2062 case L2CAP_MODE_STREAMING:
2063 case L2CAP_MODE_ERTM:
2064 if (l2cap_mode_supported(mode, remote_feat_mask))
2065 return mode;
2066 /* fall through */
2067 default:
2068 return L2CAP_MODE_BASIC;
2069 }
2070}
2071
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002072static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2073{
2074 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2075}
2076
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002077static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2078{
2079 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2080}
2081
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002082static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2083{
2084 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002085 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002086 /* use extended control field */
2087 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002088 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2089 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002090 chan->tx_win = min_t(u16, chan->tx_win,
2091 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002092 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2093 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002094}
2095
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002096static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002099 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002101 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002103 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002105 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002106 goto done;
2107
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002108 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002109 case L2CAP_MODE_STREAMING:
2110 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002111 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002112 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002113
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002114 if (__l2cap_efs_supported(chan))
2115 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2116
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002117 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002118 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002119 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002120 break;
2121 }
2122
2123done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002124 if (chan->imtu != L2CAP_DEFAULT_MTU)
2125 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002126
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002127 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002128 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002129 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2130 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002131 break;
2132
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002133 rfc.mode = L2CAP_MODE_BASIC;
2134 rfc.txwin_size = 0;
2135 rfc.max_transmit = 0;
2136 rfc.retrans_timeout = 0;
2137 rfc.monitor_timeout = 0;
2138 rfc.max_pdu_size = 0;
2139
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002140 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2141 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002142 break;
2143
2144 case L2CAP_MODE_ERTM:
2145 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002146 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002147 rfc.retrans_timeout = 0;
2148 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002149
2150 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2151 L2CAP_EXT_HDR_SIZE -
2152 L2CAP_SDULEN_SIZE -
2153 L2CAP_FCS_SIZE);
2154 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002155
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002156 l2cap_txwin_setup(chan);
2157
2158 rfc.txwin_size = min_t(u16, chan->tx_win,
2159 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002160
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002161 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2162 (unsigned long) &rfc);
2163
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002164 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2165 l2cap_add_opt_efs(&ptr, chan);
2166
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002167 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002168 break;
2169
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002170 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002171 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002172 chan->fcs = L2CAP_FCS_NONE;
2173 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002174 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002175
2176 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2177 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2178 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002179 break;
2180
2181 case L2CAP_MODE_STREAMING:
2182 rfc.mode = L2CAP_MODE_STREAMING;
2183 rfc.txwin_size = 0;
2184 rfc.max_transmit = 0;
2185 rfc.retrans_timeout = 0;
2186 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002187
2188 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2189 L2CAP_EXT_HDR_SIZE -
2190 L2CAP_SDULEN_SIZE -
2191 L2CAP_FCS_SIZE);
2192 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002193
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002194 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2195 (unsigned long) &rfc);
2196
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002197 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2198 l2cap_add_opt_efs(&ptr, chan);
2199
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002200 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002201 break;
2202
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002203 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002204 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002205 chan->fcs = L2CAP_FCS_NONE;
2206 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002207 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002208 break;
2209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002211 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002212 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213
2214 return ptr - data;
2215}
2216
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002217static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002219 struct l2cap_conf_rsp *rsp = data;
2220 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002221 void *req = chan->conf_req;
2222 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002223 int type, hint, olen;
2224 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002225 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002226 struct l2cap_conf_efs efs;
2227 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002228 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002229 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002230 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002232 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002233
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002234 while (len >= L2CAP_CONF_OPT_SIZE) {
2235 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002237 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002238 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002239
2240 switch (type) {
2241 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002242 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002243 break;
2244
2245 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002246 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002247 break;
2248
2249 case L2CAP_CONF_QOS:
2250 break;
2251
Marcel Holtmann6464f352007-10-20 13:39:51 +02002252 case L2CAP_CONF_RFC:
2253 if (olen == sizeof(rfc))
2254 memcpy(&rfc, (void *) val, olen);
2255 break;
2256
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002257 case L2CAP_CONF_FCS:
2258 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002259 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002260 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002261
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002262 case L2CAP_CONF_EFS:
2263 remote_efs = 1;
2264 if (olen == sizeof(efs))
2265 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002266 break;
2267
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002268 case L2CAP_CONF_EWS:
2269 if (!enable_hs)
2270 return -ECONNREFUSED;
2271
2272 set_bit(FLAG_EXT_CTRL, &chan->flags);
2273 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002274 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002275 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002276 break;
2277
2278 default:
2279 if (hint)
2280 break;
2281
2282 result = L2CAP_CONF_UNKNOWN;
2283 *((u8 *) ptr++) = type;
2284 break;
2285 }
2286 }
2287
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002288 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002289 goto done;
2290
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002291 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002292 case L2CAP_MODE_STREAMING:
2293 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002294 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002295 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002296 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002297 break;
2298 }
2299
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002300 if (remote_efs) {
2301 if (__l2cap_efs_supported(chan))
2302 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2303 else
2304 return -ECONNREFUSED;
2305 }
2306
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002307 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002308 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002309
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002310 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002311 }
2312
2313done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002314 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002315 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002316 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002317
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002318 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002319 return -ECONNREFUSED;
2320
2321 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2322 sizeof(rfc), (unsigned long) &rfc);
2323 }
2324
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002325 if (result == L2CAP_CONF_SUCCESS) {
2326 /* Configure output options and let the other side know
2327 * which ones we don't like. */
2328
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002329 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2330 result = L2CAP_CONF_UNACCEPT;
2331 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002332 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002333 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002334 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002335 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002336
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002337 if (remote_efs) {
2338 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2339 efs.stype != L2CAP_SERV_NOTRAFIC &&
2340 efs.stype != chan->local_stype) {
2341
2342 result = L2CAP_CONF_UNACCEPT;
2343
2344 if (chan->num_conf_req >= 1)
2345 return -ECONNREFUSED;
2346
2347 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002348 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002349 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002350 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002351 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002352 result = L2CAP_CONF_PENDING;
2353 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002354 }
2355 }
2356
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002357 switch (rfc.mode) {
2358 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002359 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002360 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002361 break;
2362
2363 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002364 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2365 chan->remote_tx_win = rfc.txwin_size;
2366 else
2367 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2368
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002369 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002370
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002371 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2372 chan->conn->mtu -
2373 L2CAP_EXT_HDR_SIZE -
2374 L2CAP_SDULEN_SIZE -
2375 L2CAP_FCS_SIZE);
2376 rfc.max_pdu_size = cpu_to_le16(size);
2377 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002378
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002379 rfc.retrans_timeout =
2380 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2381 rfc.monitor_timeout =
2382 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002383
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002384 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002385
2386 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2387 sizeof(rfc), (unsigned long) &rfc);
2388
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002389 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2390 chan->remote_id = efs.id;
2391 chan->remote_stype = efs.stype;
2392 chan->remote_msdu = le16_to_cpu(efs.msdu);
2393 chan->remote_flush_to =
2394 le32_to_cpu(efs.flush_to);
2395 chan->remote_acc_lat =
2396 le32_to_cpu(efs.acc_lat);
2397 chan->remote_sdu_itime =
2398 le32_to_cpu(efs.sdu_itime);
2399 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2400 sizeof(efs), (unsigned long) &efs);
2401 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002402 break;
2403
2404 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002405 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2406 chan->conn->mtu -
2407 L2CAP_EXT_HDR_SIZE -
2408 L2CAP_SDULEN_SIZE -
2409 L2CAP_FCS_SIZE);
2410 rfc.max_pdu_size = cpu_to_le16(size);
2411 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002412
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002413 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002414
2415 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2416 sizeof(rfc), (unsigned long) &rfc);
2417
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002418 break;
2419
2420 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002421 result = L2CAP_CONF_UNACCEPT;
2422
2423 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002424 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002425 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002426
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002427 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002428 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002429 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002430 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002431 rsp->result = cpu_to_le16(result);
2432 rsp->flags = cpu_to_le16(0x0000);
2433
2434 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435}
2436
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002437static 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 -03002438{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002439 struct l2cap_conf_req *req = data;
2440 void *ptr = req->data;
2441 int type, olen;
2442 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002443 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002444 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002445
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002446 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002447
2448 while (len >= L2CAP_CONF_OPT_SIZE) {
2449 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2450
2451 switch (type) {
2452 case L2CAP_CONF_MTU:
2453 if (val < L2CAP_DEFAULT_MIN_MTU) {
2454 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002455 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002456 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002457 chan->imtu = val;
2458 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002459 break;
2460
2461 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002462 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002463 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002464 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002465 break;
2466
2467 case L2CAP_CONF_RFC:
2468 if (olen == sizeof(rfc))
2469 memcpy(&rfc, (void *)val, olen);
2470
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002471 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002472 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002473 return -ECONNREFUSED;
2474
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002475 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002476
2477 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2478 sizeof(rfc), (unsigned long) &rfc);
2479 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002480
2481 case L2CAP_CONF_EWS:
2482 chan->tx_win = min_t(u16, val,
2483 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002484 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2485 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002486 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002487
2488 case L2CAP_CONF_EFS:
2489 if (olen == sizeof(efs))
2490 memcpy(&efs, (void *)val, olen);
2491
2492 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2493 efs.stype != L2CAP_SERV_NOTRAFIC &&
2494 efs.stype != chan->local_stype)
2495 return -ECONNREFUSED;
2496
2497 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2498 sizeof(efs), (unsigned long) &efs);
2499 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002500 }
2501 }
2502
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002503 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002504 return -ECONNREFUSED;
2505
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002506 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002507
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002508 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002509 switch (rfc.mode) {
2510 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002511 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2512 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2513 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002514
2515 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2516 chan->local_msdu = le16_to_cpu(efs.msdu);
2517 chan->local_sdu_itime =
2518 le32_to_cpu(efs.sdu_itime);
2519 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2520 chan->local_flush_to =
2521 le32_to_cpu(efs.flush_to);
2522 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002523 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002524
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002525 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002526 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002527 }
2528 }
2529
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002530 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002531 req->flags = cpu_to_le16(0x0000);
2532
2533 return ptr - data;
2534}
2535
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002536static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537{
2538 struct l2cap_conf_rsp *rsp = data;
2539 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002541 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002543 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002544 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002545 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546
2547 return ptr - data;
2548}
2549
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002550void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002551{
2552 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002553 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002554 u8 buf[128];
2555
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002556 rsp.scid = cpu_to_le16(chan->dcid);
2557 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002558 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2559 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2560 l2cap_send_cmd(conn, chan->ident,
2561 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2562
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002563 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002564 return;
2565
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002566 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2567 l2cap_build_conf_req(chan, buf), buf);
2568 chan->num_conf_req++;
2569}
2570
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002571static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002572{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002573 int type, olen;
2574 unsigned long val;
2575 struct l2cap_conf_rfc rfc;
2576
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002577 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002578
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002579 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002580 return;
2581
2582 while (len >= L2CAP_CONF_OPT_SIZE) {
2583 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2584
2585 switch (type) {
2586 case L2CAP_CONF_RFC:
2587 if (olen == sizeof(rfc))
2588 memcpy(&rfc, (void *)val, olen);
2589 goto done;
2590 }
2591 }
2592
Mat Martineau36e999a2011-12-08 17:23:21 -08002593 /* Use sane default values in case a misbehaving remote device
2594 * did not send an RFC option.
2595 */
2596 rfc.mode = chan->mode;
2597 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2598 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2599 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2600
2601 BT_ERR("Expected RFC option was not found, using defaults");
2602
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002603done:
2604 switch (rfc.mode) {
2605 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002606 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2607 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2608 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002609 break;
2610 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002611 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002612 }
2613}
2614
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002615static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2616{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002617 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002618
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002619 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002620 return 0;
2621
2622 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2623 cmd->ident == conn->info_ident) {
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02002624 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002625
2626 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002627 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002628
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002629 l2cap_conn_start(conn);
2630 }
2631
2632 return 0;
2633}
2634
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2636{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2638 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002639 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002640 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002641 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642
2643 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002644 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
2646 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2647
2648 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002649 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2650 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 result = L2CAP_CR_BAD_PSM;
2652 goto sendresp;
2653 }
2654
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002655 parent = pchan->sk;
2656
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002657 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002658 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002659
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002660 /* Check if the ACL is secure enough (if not SDP) */
2661 if (psm != cpu_to_le16(0x0001) &&
2662 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002663 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002664 result = L2CAP_CR_SEC_BLOCK;
2665 goto response;
2666 }
2667
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 result = L2CAP_CR_NO_MEM;
2669
2670 /* Check for backlog size */
2671 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002672 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 goto response;
2674 }
2675
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002676 chan = pchan->ops->new_connection(pchan->data);
2677 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 goto response;
2679
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002680 sk = chan->sk;
2681
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002683 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002685 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 goto response;
2687 }
2688
2689 hci_conn_hold(conn->hcon);
2690
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 bacpy(&bt_sk(sk)->src, conn->src);
2692 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002693 chan->psm = psm;
2694 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002696 bt_accept_enqueue(parent, sk);
2697
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002698 __l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002699
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002700 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002702 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002704 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
Marcel Holtmann984947d2009-02-06 23:35:19 +01002706 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002707 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002708 if (bt_sk(sk)->defer_setup) {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002709 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002710 result = L2CAP_CR_PEND;
2711 status = L2CAP_CS_AUTHOR_PEND;
2712 parent->sk_data_ready(parent, 0);
2713 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002714 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002715 result = L2CAP_CR_SUCCESS;
2716 status = L2CAP_CS_NO_INFO;
2717 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002718 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002719 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002720 result = L2CAP_CR_PEND;
2721 status = L2CAP_CS_AUTHEN_PEND;
2722 }
2723 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002724 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002725 result = L2CAP_CR_PEND;
2726 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 }
2728
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002730 release_sock(parent);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002731 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732
2733sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002734 rsp.scid = cpu_to_le16(scid);
2735 rsp.dcid = cpu_to_le16(dcid);
2736 rsp.result = cpu_to_le16(result);
2737 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002739
2740 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2741 struct l2cap_info_req info;
2742 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2743
2744 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2745 conn->info_ident = l2cap_get_ident(conn);
2746
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02002747 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002748 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2749
2750 l2cap_send_cmd(conn, conn->info_ident,
2751 L2CAP_INFO_REQ, sizeof(info), &info);
2752 }
2753
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002754 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002755 result == L2CAP_CR_SUCCESS) {
2756 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002757 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002758 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002759 l2cap_build_conf_req(chan, buf), buf);
2760 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002761 }
2762
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 return 0;
2764}
2765
2766static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2767{
2768 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2769 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002770 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 u8 req[128];
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002772 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773
2774 scid = __le16_to_cpu(rsp->scid);
2775 dcid = __le16_to_cpu(rsp->dcid);
2776 result = __le16_to_cpu(rsp->result);
2777 status = __le16_to_cpu(rsp->status);
2778
Andrei Emeltchenko1b009c92012-02-21 12:54:54 +02002779 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
2780 dcid, scid, result, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002782 mutex_lock(&conn->chan_lock);
2783
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 if (scid) {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002785 chan = __l2cap_get_chan_by_scid(conn, scid);
2786 if (!chan) {
2787 err = -EFAULT;
2788 goto unlock;
2789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 } else {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002791 chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
2792 if (!chan) {
2793 err = -EFAULT;
2794 goto unlock;
2795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 }
2797
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002798 err = 0;
2799
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002800 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002801
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 switch (result) {
2803 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002804 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002805 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002806 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002807 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002808
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002809 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002810 break;
2811
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002813 l2cap_build_conf_req(chan, req), req);
2814 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 break;
2816
2817 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002818 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 break;
2820
2821 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002822 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 break;
2824 }
2825
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002826 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002827
2828unlock:
2829 mutex_unlock(&conn->chan_lock);
2830
2831 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832}
2833
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002834static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002835{
2836 /* FCS is enabled only in ERTM or streaming mode, if one or both
2837 * sides request it.
2838 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002839 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002840 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002841 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002842 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002843}
2844
Al Viro88219a02007-07-29 00:17:25 -07002845static 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 -07002846{
2847 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2848 u16 dcid, flags;
2849 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002850 struct l2cap_chan *chan;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002851 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
2853 dcid = __le16_to_cpu(req->dcid);
2854 flags = __le16_to_cpu(req->flags);
2855
2856 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2857
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002858 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002859 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 return -ENOENT;
2861
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002862 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002863
David S. Miller033b1142011-07-21 13:38:42 -07002864 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002865 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002866
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002867 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2868 rej.scid = cpu_to_le16(chan->scid);
2869 rej.dcid = cpu_to_le16(chan->dcid);
2870
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002871 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2872 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002873 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002874 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002875
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002876 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002877 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002878 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002879 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002880 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002881 L2CAP_CONF_REJECT, flags), rsp);
2882 goto unlock;
2883 }
2884
2885 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002886 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2887 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888
2889 if (flags & 0x0001) {
2890 /* Incomplete config. Send empty response. */
2891 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002892 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002893 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 goto unlock;
2895 }
2896
2897 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002898 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002899 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002900 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002904 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002905 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002906
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002907 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002908 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002909
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002910 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002911 goto unlock;
2912
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002913 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002914 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002915
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002916 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002917
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002918 chan->next_tx_seq = 0;
2919 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002920 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002921 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002922 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002923
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02002924 l2cap_chan_ready(chan);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002925 goto unlock;
2926 }
2927
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002928 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002929 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002931 l2cap_build_conf_req(chan, buf), buf);
2932 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 }
2934
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002935 /* Got Conf Rsp PENDING from remote side and asume we sent
2936 Conf Rsp PENDING in the code above */
2937 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2938 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2939
2940 /* check compatibility */
2941
2942 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2943 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2944
2945 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002946 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002947 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2948 }
2949
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950unlock:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002951 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 return 0;
2953}
2954
2955static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2956{
2957 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2958 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002959 struct l2cap_chan *chan;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002960 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961
2962 scid = __le16_to_cpu(rsp->scid);
2963 flags = __le16_to_cpu(rsp->flags);
2964 result = __le16_to_cpu(rsp->result);
2965
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002966 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2967 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002969 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002970 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 return 0;
2972
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002973 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002974
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 switch (result) {
2976 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002977 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002978 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 break;
2980
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002981 case L2CAP_CONF_PENDING:
2982 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2983
2984 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2985 char buf[64];
2986
2987 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2988 buf, &result);
2989 if (len < 0) {
2990 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2991 goto done;
2992 }
2993
2994 /* check compatibility */
2995
2996 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2997 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2998
2999 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02003000 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03003001 L2CAP_CONF_SUCCESS, 0x0000), buf);
3002 }
3003 goto done;
3004
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003006 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003007 char req[64];
3008
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003009 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003010 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003011 goto done;
3012 }
3013
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003014 /* throw out any old stored conf requests */
3015 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03003016 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
3017 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003018 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003019 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003020 goto done;
3021 }
3022
3023 l2cap_send_cmd(conn, l2cap_get_ident(conn),
3024 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003025 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003026 if (result != L2CAP_CONF_SUCCESS)
3027 goto done;
3028 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 }
3030
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09003031 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003032 l2cap_chan_set_err(chan, ECONNRESET);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +02003033
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01003034 __set_chan_timer(chan,
3035 msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT));
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003036 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 goto done;
3038 }
3039
3040 if (flags & 0x01)
3041 goto done;
3042
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003043 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003045 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003046 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003047
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003048 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003049 chan->next_tx_seq = 0;
3050 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003051 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003052 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003053 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003054
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02003055 l2cap_chan_ready(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 }
3057
3058done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003059 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 return 0;
3061}
3062
3063static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3064{
3065 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3066 struct l2cap_disconn_rsp rsp;
3067 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003068 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 struct sock *sk;
3070
3071 scid = __le16_to_cpu(req->scid);
3072 dcid = __le16_to_cpu(req->dcid);
3073
3074 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3075
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003076 mutex_lock(&conn->chan_lock);
3077
3078 chan = __l2cap_get_chan_by_scid(conn, dcid);
3079 if (!chan) {
3080 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003084 l2cap_chan_lock(chan);
3085
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003086 sk = chan->sk;
3087
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003088 rsp.dcid = cpu_to_le16(chan->scid);
3089 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3091
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003092 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 sk->sk_shutdown = SHUTDOWN_MASK;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003094 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003096 l2cap_chan_del(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003097
3098 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003100 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003101
3102 mutex_unlock(&conn->chan_lock);
3103
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 return 0;
3105}
3106
3107static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3108{
3109 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3110 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003111 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112
3113 scid = __le16_to_cpu(rsp->scid);
3114 dcid = __le16_to_cpu(rsp->dcid);
3115
3116 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3117
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003118 mutex_lock(&conn->chan_lock);
3119
3120 chan = __l2cap_get_chan_by_scid(conn, scid);
3121 if (!chan) {
3122 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003126 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003127
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003128 l2cap_chan_del(chan, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003129
3130 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003132 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003133
3134 mutex_unlock(&conn->chan_lock);
3135
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 return 0;
3137}
3138
3139static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3140{
3141 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 u16 type;
3143
3144 type = __le16_to_cpu(req->type);
3145
3146 BT_DBG("type 0x%4.4x", type);
3147
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003148 if (type == L2CAP_IT_FEAT_MASK) {
3149 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003150 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003151 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3152 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3153 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003154 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003155 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3156 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003157 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003158 feat_mask |= L2CAP_FEAT_EXT_FLOW
3159 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003160
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003161 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003162 l2cap_send_cmd(conn, cmd->ident,
3163 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003164 } else if (type == L2CAP_IT_FIXED_CHAN) {
3165 u8 buf[12];
3166 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003167
3168 if (enable_hs)
3169 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3170 else
3171 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3172
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003173 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3174 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003175 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003176 l2cap_send_cmd(conn, cmd->ident,
3177 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003178 } else {
3179 struct l2cap_info_rsp rsp;
3180 rsp.type = cpu_to_le16(type);
3181 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3182 l2cap_send_cmd(conn, cmd->ident,
3183 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
3186 return 0;
3187}
3188
3189static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3190{
3191 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3192 u16 type, result;
3193
3194 type = __le16_to_cpu(rsp->type);
3195 result = __le16_to_cpu(rsp->result);
3196
3197 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3198
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003199 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3200 if (cmd->ident != conn->info_ident ||
3201 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3202 return 0;
3203
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02003204 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003205
Ville Tervoadb08ed2010-08-04 09:43:33 +03003206 if (result != L2CAP_IR_SUCCESS) {
3207 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3208 conn->info_ident = 0;
3209
3210 l2cap_conn_start(conn);
3211
3212 return 0;
3213 }
3214
Marcel Holtmann984947d2009-02-06 23:35:19 +01003215 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003216 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003217
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003218 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003219 struct l2cap_info_req req;
3220 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3221
3222 conn->info_ident = l2cap_get_ident(conn);
3223
3224 l2cap_send_cmd(conn, conn->info_ident,
3225 L2CAP_INFO_REQ, sizeof(req), &req);
3226 } else {
3227 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3228 conn->info_ident = 0;
3229
3230 l2cap_conn_start(conn);
3231 }
3232 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003233 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003234 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003235
3236 l2cap_conn_start(conn);
3237 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003238
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 return 0;
3240}
3241
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003242static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3243 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3244 void *data)
3245{
3246 struct l2cap_create_chan_req *req = data;
3247 struct l2cap_create_chan_rsp rsp;
3248 u16 psm, scid;
3249
3250 if (cmd_len != sizeof(*req))
3251 return -EPROTO;
3252
3253 if (!enable_hs)
3254 return -EINVAL;
3255
3256 psm = le16_to_cpu(req->psm);
3257 scid = le16_to_cpu(req->scid);
3258
3259 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3260
3261 /* Placeholder: Always reject */
3262 rsp.dcid = 0;
3263 rsp.scid = cpu_to_le16(scid);
3264 rsp.result = L2CAP_CR_NO_MEM;
3265 rsp.status = L2CAP_CS_NO_INFO;
3266
3267 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3268 sizeof(rsp), &rsp);
3269
3270 return 0;
3271}
3272
3273static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3274 struct l2cap_cmd_hdr *cmd, void *data)
3275{
3276 BT_DBG("conn %p", conn);
3277
3278 return l2cap_connect_rsp(conn, cmd, data);
3279}
3280
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003281static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3282 u16 icid, u16 result)
3283{
3284 struct l2cap_move_chan_rsp rsp;
3285
3286 BT_DBG("icid %d, result %d", icid, result);
3287
3288 rsp.icid = cpu_to_le16(icid);
3289 rsp.result = cpu_to_le16(result);
3290
3291 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3292}
3293
3294static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3295 struct l2cap_chan *chan, u16 icid, u16 result)
3296{
3297 struct l2cap_move_chan_cfm cfm;
3298 u8 ident;
3299
3300 BT_DBG("icid %d, result %d", icid, result);
3301
3302 ident = l2cap_get_ident(conn);
3303 if (chan)
3304 chan->ident = ident;
3305
3306 cfm.icid = cpu_to_le16(icid);
3307 cfm.result = cpu_to_le16(result);
3308
3309 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3310}
3311
3312static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3313 u16 icid)
3314{
3315 struct l2cap_move_chan_cfm_rsp rsp;
3316
3317 BT_DBG("icid %d", icid);
3318
3319 rsp.icid = cpu_to_le16(icid);
3320 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3321}
3322
3323static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3324 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3325{
3326 struct l2cap_move_chan_req *req = data;
3327 u16 icid = 0;
3328 u16 result = L2CAP_MR_NOT_ALLOWED;
3329
3330 if (cmd_len != sizeof(*req))
3331 return -EPROTO;
3332
3333 icid = le16_to_cpu(req->icid);
3334
3335 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3336
3337 if (!enable_hs)
3338 return -EINVAL;
3339
3340 /* Placeholder: Always refuse */
3341 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3342
3343 return 0;
3344}
3345
3346static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3347 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3348{
3349 struct l2cap_move_chan_rsp *rsp = data;
3350 u16 icid, result;
3351
3352 if (cmd_len != sizeof(*rsp))
3353 return -EPROTO;
3354
3355 icid = le16_to_cpu(rsp->icid);
3356 result = le16_to_cpu(rsp->result);
3357
3358 BT_DBG("icid %d, result %d", icid, result);
3359
3360 /* Placeholder: Always unconfirmed */
3361 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3362
3363 return 0;
3364}
3365
3366static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3367 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3368{
3369 struct l2cap_move_chan_cfm *cfm = data;
3370 u16 icid, result;
3371
3372 if (cmd_len != sizeof(*cfm))
3373 return -EPROTO;
3374
3375 icid = le16_to_cpu(cfm->icid);
3376 result = le16_to_cpu(cfm->result);
3377
3378 BT_DBG("icid %d, result %d", icid, result);
3379
3380 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3381
3382 return 0;
3383}
3384
3385static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3386 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3387{
3388 struct l2cap_move_chan_cfm_rsp *rsp = data;
3389 u16 icid;
3390
3391 if (cmd_len != sizeof(*rsp))
3392 return -EPROTO;
3393
3394 icid = le16_to_cpu(rsp->icid);
3395
3396 BT_DBG("icid %d", icid);
3397
3398 return 0;
3399}
3400
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003401static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003402 u16 to_multiplier)
3403{
3404 u16 max_latency;
3405
3406 if (min > max || min < 6 || max > 3200)
3407 return -EINVAL;
3408
3409 if (to_multiplier < 10 || to_multiplier > 3200)
3410 return -EINVAL;
3411
3412 if (max >= to_multiplier * 8)
3413 return -EINVAL;
3414
3415 max_latency = (to_multiplier * 8 / max) - 1;
3416 if (latency > 499 || latency > max_latency)
3417 return -EINVAL;
3418
3419 return 0;
3420}
3421
3422static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3423 struct l2cap_cmd_hdr *cmd, u8 *data)
3424{
3425 struct hci_conn *hcon = conn->hcon;
3426 struct l2cap_conn_param_update_req *req;
3427 struct l2cap_conn_param_update_rsp rsp;
3428 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003429 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003430
3431 if (!(hcon->link_mode & HCI_LM_MASTER))
3432 return -EINVAL;
3433
3434 cmd_len = __le16_to_cpu(cmd->len);
3435 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3436 return -EPROTO;
3437
3438 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003439 min = __le16_to_cpu(req->min);
3440 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003441 latency = __le16_to_cpu(req->latency);
3442 to_multiplier = __le16_to_cpu(req->to_multiplier);
3443
3444 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3445 min, max, latency, to_multiplier);
3446
3447 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003448
3449 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3450 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003451 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3452 else
3453 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3454
3455 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3456 sizeof(rsp), &rsp);
3457
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003458 if (!err)
3459 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3460
Claudio Takahaside731152011-02-11 19:28:55 -02003461 return 0;
3462}
3463
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003464static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3465 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3466{
3467 int err = 0;
3468
3469 switch (cmd->code) {
3470 case L2CAP_COMMAND_REJ:
3471 l2cap_command_rej(conn, cmd, data);
3472 break;
3473
3474 case L2CAP_CONN_REQ:
3475 err = l2cap_connect_req(conn, cmd, data);
3476 break;
3477
3478 case L2CAP_CONN_RSP:
3479 err = l2cap_connect_rsp(conn, cmd, data);
3480 break;
3481
3482 case L2CAP_CONF_REQ:
3483 err = l2cap_config_req(conn, cmd, cmd_len, data);
3484 break;
3485
3486 case L2CAP_CONF_RSP:
3487 err = l2cap_config_rsp(conn, cmd, data);
3488 break;
3489
3490 case L2CAP_DISCONN_REQ:
3491 err = l2cap_disconnect_req(conn, cmd, data);
3492 break;
3493
3494 case L2CAP_DISCONN_RSP:
3495 err = l2cap_disconnect_rsp(conn, cmd, data);
3496 break;
3497
3498 case L2CAP_ECHO_REQ:
3499 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3500 break;
3501
3502 case L2CAP_ECHO_RSP:
3503 break;
3504
3505 case L2CAP_INFO_REQ:
3506 err = l2cap_information_req(conn, cmd, data);
3507 break;
3508
3509 case L2CAP_INFO_RSP:
3510 err = l2cap_information_rsp(conn, cmd, data);
3511 break;
3512
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003513 case L2CAP_CREATE_CHAN_REQ:
3514 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3515 break;
3516
3517 case L2CAP_CREATE_CHAN_RSP:
3518 err = l2cap_create_channel_rsp(conn, cmd, data);
3519 break;
3520
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003521 case L2CAP_MOVE_CHAN_REQ:
3522 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3523 break;
3524
3525 case L2CAP_MOVE_CHAN_RSP:
3526 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3527 break;
3528
3529 case L2CAP_MOVE_CHAN_CFM:
3530 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3531 break;
3532
3533 case L2CAP_MOVE_CHAN_CFM_RSP:
3534 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3535 break;
3536
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003537 default:
3538 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3539 err = -EINVAL;
3540 break;
3541 }
3542
3543 return err;
3544}
3545
3546static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3547 struct l2cap_cmd_hdr *cmd, u8 *data)
3548{
3549 switch (cmd->code) {
3550 case L2CAP_COMMAND_REJ:
3551 return 0;
3552
3553 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003554 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003555
3556 case L2CAP_CONN_PARAM_UPDATE_RSP:
3557 return 0;
3558
3559 default:
3560 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3561 return -EINVAL;
3562 }
3563}
3564
3565static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3566 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567{
3568 u8 *data = skb->data;
3569 int len = skb->len;
3570 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003571 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
3573 l2cap_raw_recv(conn, skb);
3574
3575 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003576 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3578 data += L2CAP_CMD_HDR_SIZE;
3579 len -= L2CAP_CMD_HDR_SIZE;
3580
Al Viro88219a02007-07-29 00:17:25 -07003581 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582
Al Viro88219a02007-07-29 00:17:25 -07003583 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 -07003584
Al Viro88219a02007-07-29 00:17:25 -07003585 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 BT_DBG("corrupted command");
3587 break;
3588 }
3589
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003590 if (conn->hcon->type == LE_LINK)
3591 err = l2cap_le_sig_cmd(conn, &cmd, data);
3592 else
3593 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594
3595 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003596 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003597
3598 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599
3600 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003601 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3603 }
3604
Al Viro88219a02007-07-29 00:17:25 -07003605 data += cmd_len;
3606 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 }
3608
3609 kfree_skb(skb);
3610}
3611
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003612static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003613{
3614 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003615 int hdr_size;
3616
3617 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3618 hdr_size = L2CAP_EXT_HDR_SIZE;
3619 else
3620 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003621
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003622 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003623 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003624 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3625 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3626
3627 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003628 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003629 }
3630 return 0;
3631}
3632
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003633static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003634{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003635 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003636
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003637 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003638
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003639 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003640
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003641 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003642 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003643 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003644 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003645 }
3646
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003647 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003648 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003649
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003650 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003651
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003652 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003653 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003654 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003655 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003656 }
3657}
3658
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003659static 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 -03003660{
3661 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003662 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003663
3664 bt_cb(skb)->tx_seq = tx_seq;
3665 bt_cb(skb)->sar = sar;
3666
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003667 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003668
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003669 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003670
Szymon Janc039d9572011-11-16 09:32:19 +01003671 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003672 if (bt_cb(next_skb)->tx_seq == tx_seq)
3673 return -EINVAL;
3674
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003675 next_tx_seq_offset = __seq_offset(chan,
3676 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003677
3678 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003679 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003680 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003681 }
3682
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003683 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003684 next_skb = NULL;
3685 else
3686 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3687 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003688
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003689 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003690
3691 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003692}
3693
Mat Martineau84084a32011-07-22 14:54:00 -07003694static void append_skb_frag(struct sk_buff *skb,
3695 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003696{
Mat Martineau84084a32011-07-22 14:54:00 -07003697 /* skb->len reflects data in skb as well as all fragments
3698 * skb->data_len reflects only data in fragments
3699 */
3700 if (!skb_has_frag_list(skb))
3701 skb_shinfo(skb)->frag_list = new_frag;
3702
3703 new_frag->next = NULL;
3704
3705 (*last_frag)->next = new_frag;
3706 *last_frag = new_frag;
3707
3708 skb->len += new_frag->len;
3709 skb->data_len += new_frag->len;
3710 skb->truesize += new_frag->truesize;
3711}
3712
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003713static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003714{
3715 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003716
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003717 switch (__get_ctrl_sar(chan, control)) {
3718 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003719 if (chan->sdu)
3720 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003721
Mat Martineau84084a32011-07-22 14:54:00 -07003722 err = chan->ops->recv(chan->data, skb);
3723 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003724
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003725 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003726 if (chan->sdu)
3727 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003728
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003729 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003730 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003731
Mat Martineau84084a32011-07-22 14:54:00 -07003732 if (chan->sdu_len > chan->imtu) {
3733 err = -EMSGSIZE;
3734 break;
3735 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003736
Mat Martineau84084a32011-07-22 14:54:00 -07003737 if (skb->len >= chan->sdu_len)
3738 break;
3739
3740 chan->sdu = skb;
3741 chan->sdu_last_frag = skb;
3742
3743 skb = NULL;
3744 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003745 break;
3746
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003747 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003748 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003749 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003750
Mat Martineau84084a32011-07-22 14:54:00 -07003751 append_skb_frag(chan->sdu, skb,
3752 &chan->sdu_last_frag);
3753 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003754
Mat Martineau84084a32011-07-22 14:54:00 -07003755 if (chan->sdu->len >= chan->sdu_len)
3756 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003757
Mat Martineau84084a32011-07-22 14:54:00 -07003758 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003759 break;
3760
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003761 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003762 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003763 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003764
Mat Martineau84084a32011-07-22 14:54:00 -07003765 append_skb_frag(chan->sdu, skb,
3766 &chan->sdu_last_frag);
3767 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003768
Mat Martineau84084a32011-07-22 14:54:00 -07003769 if (chan->sdu->len != chan->sdu_len)
3770 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003771
Mat Martineau84084a32011-07-22 14:54:00 -07003772 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003773
Mat Martineau84084a32011-07-22 14:54:00 -07003774 if (!err) {
3775 /* Reassembly complete */
3776 chan->sdu = NULL;
3777 chan->sdu_last_frag = NULL;
3778 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003779 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003780 break;
3781 }
3782
Mat Martineau84084a32011-07-22 14:54:00 -07003783 if (err) {
3784 kfree_skb(skb);
3785 kfree_skb(chan->sdu);
3786 chan->sdu = NULL;
3787 chan->sdu_last_frag = NULL;
3788 chan->sdu_len = 0;
3789 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003790
Mat Martineau84084a32011-07-22 14:54:00 -07003791 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003792}
3793
Mat Martineau26f880d2011-07-07 09:39:01 -07003794static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003795{
Mat Martineau26f880d2011-07-07 09:39:01 -07003796 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003797
Mat Martineau26f880d2011-07-07 09:39:01 -07003798 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3799
Szymon Janc77f918b2012-01-11 10:59:48 +01003800 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003801}
3802
3803static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3804{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003805 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003806
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003807 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003808 goto done;
3809
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003810 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003811 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003812 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003813 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003814 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003815
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003816 __clear_retrans_timer(chan);
3817 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003818
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003819 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003820
3821done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003822 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3823 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003824
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003825 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003826}
3827
Mat Martineaue3281402011-07-07 09:39:02 -07003828void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003829{
Mat Martineaue3281402011-07-07 09:39:02 -07003830 if (chan->mode == L2CAP_MODE_ERTM) {
3831 if (busy)
3832 l2cap_ertm_enter_local_busy(chan);
3833 else
3834 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003835 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003836}
3837
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003838static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003839{
3840 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003841 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003842
Mat Martineaue3281402011-07-07 09:39:02 -07003843 while ((skb = skb_peek(&chan->srej_q)) &&
3844 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3845 int err;
3846
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003847 if (bt_cb(skb)->tx_seq != tx_seq)
3848 break;
3849
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003850 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003851 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003852 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003853
3854 if (err < 0) {
3855 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3856 break;
3857 }
3858
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003859 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3860 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003861 }
3862}
3863
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003864static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003865{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003866 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003867 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003868
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003869 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003870 if (l->tx_seq == tx_seq) {
3871 list_del(&l->list);
3872 kfree(l);
3873 return;
3874 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003875 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003876 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003877 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003878 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003879 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003880 }
3881}
3882
Szymon Jancaef89f22011-11-16 09:32:18 +01003883static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003884{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003885 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003886 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003887
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003888 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003889 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003890 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003891 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003892
3893 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003894 if (!new)
3895 return -ENOMEM;
3896
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003897 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003898
3899 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3900
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003901 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003902 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003903
3904 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003905
3906 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003907}
3908
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003909static 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 -03003910{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003911 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003912 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003913 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003914 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003915 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003916 int err = 0;
3917
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003918 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 -03003919 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003920
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003921 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003922 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003923 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003924 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003925 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003926 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003927 }
3928
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003929 chan->expected_ack_seq = req_seq;
3930 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003931
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003932 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003933
3934 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003935 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003936 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003937 goto drop;
3938 }
3939
Szymon Janc77f918b2012-01-11 10:59:48 +01003940 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3941 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3942 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003943 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003944 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003945
Mat Martineau02f1b642011-06-29 14:35:19 -07003946 if (tx_seq == chan->expected_tx_seq)
3947 goto expected;
3948
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003949 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003950 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003951
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003952 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003953 struct srej_list, list);
3954 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003955 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003956 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003957
3958 list_del(&first->list);
3959 kfree(first);
3960
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003961 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003962 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003963 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003964 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003965 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003966 }
3967 } else {
3968 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003969
3970 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003971 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003972 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003973
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003974 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003975 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003976 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003977 return 0;
3978 }
3979 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003980
3981 err = l2cap_send_srejframe(chan, tx_seq);
3982 if (err < 0) {
3983 l2cap_send_disconn_req(chan->conn, chan, -err);
3984 return err;
3985 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003986 }
3987 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003988 expected_tx_seq_offset = __seq_offset(chan,
3989 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003990
3991 /* duplicated tx_seq */
3992 if (tx_seq_offset < expected_tx_seq_offset)
3993 goto drop;
3994
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003995 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003996
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003997 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003998
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003999 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004000 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004001
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004002 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004003 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004004
Szymon Janc0ef3ef02012-01-11 10:59:46 +01004005 /* Set P-bit only if there are some I-frames to ack. */
4006 if (__clear_ack_timer(chan))
4007 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03004008
Szymon Jancaef89f22011-11-16 09:32:18 +01004009 err = l2cap_send_srejframe(chan, tx_seq);
4010 if (err < 0) {
4011 l2cap_send_disconn_req(chan->conn, chan, -err);
4012 return err;
4013 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004014 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004015 return 0;
4016
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004017expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004018 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004019
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004020 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03004021 bt_cb(skb)->tx_seq = tx_seq;
4022 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004023 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004024 return 0;
4025 }
4026
Mat Martineau84084a32011-07-22 14:54:00 -07004027 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004028 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4029
Mat Martineaue3281402011-07-07 09:39:02 -07004030 if (err < 0) {
4031 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4032 return err;
4033 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03004034
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004035 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004036 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004037 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03004038 }
4039
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03004040
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004041 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
4042 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004043 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03004044 else
4045 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03004046
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004047 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03004048
4049drop:
4050 kfree_skb(skb);
4051 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004052}
4053
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004054static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004055{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004056 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004057 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004058
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004059 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004060 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004061
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004062 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004063 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4064 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4065 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004066 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004067 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004068
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004069 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004070 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004071 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004072 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004073 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004074
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004075 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004076 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004077
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004078 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004079 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004080
4081 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004082 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004083 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004084 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004085
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004086 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4087 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004088 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004089 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004090 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004091 }
4092}
4093
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004094static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004095{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004096 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004097
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004098 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004099
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004100 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004101
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004102 chan->expected_ack_seq = tx_seq;
4103 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004104
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004105 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004106 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004107 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004108 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004109 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004110
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004111 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4112 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004113 }
4114}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004115static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004116{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004117 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004118
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004119 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004120
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004121 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004122
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004123 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004124 chan->expected_ack_seq = tx_seq;
4125 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004126
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004127 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004128 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004129
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004130 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004131
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004132 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004133 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004134 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004135 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004136 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004137 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004138 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004139 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004140 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004141 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004142 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004143 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004144 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004145 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004146 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004147 }
4148 }
4149}
4150
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004151static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004152{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004153 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004154
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004155 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004156
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004157 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004158 chan->expected_ack_seq = tx_seq;
4159 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004160
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004161 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004162 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004163
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004164 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004165 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004166 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004167 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004168 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004169 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004170
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004171 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004172 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004173 } else {
4174 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4175 l2cap_send_sframe(chan, rx_control);
4176 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004177}
4178
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004179static 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 -03004180{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004181 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004182
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004183 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004184 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004185 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004186 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004187 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004188 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004189 }
4190
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004191 switch (__get_ctrl_super(chan, rx_control)) {
4192 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004193 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004194 break;
4195
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004196 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004197 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004198 break;
4199
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004200 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004201 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004202 break;
4203
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004204 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004205 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004206 break;
4207 }
4208
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004209 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004210 return 0;
4211}
4212
Szymon Janccad8f1d02012-01-23 10:06:05 +01004213static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004214{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004215 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004216 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004217 int len, next_tx_seq_offset, req_seq_offset;
4218
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004219 control = __get_control(chan, skb->data);
4220 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004221 len = skb->len;
4222
4223 /*
4224 * We can just drop the corrupted I-frame here.
4225 * Receiver will miss it and start proper recovery
4226 * procedures and ask retransmission.
4227 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004228 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004229 goto drop;
4230
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004231 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004232 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004233
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004234 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004235 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004236
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004237 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004238 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004239 goto drop;
4240 }
4241
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004242 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004243
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004244 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4245
4246 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4247 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004248
4249 /* check for invalid req-seq */
4250 if (req_seq_offset > next_tx_seq_offset) {
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 Emeltchenko793c2f12011-10-11 13:37:48 +03004255 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004256 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004257 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004258 goto drop;
4259 }
4260
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004261 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004262 } else {
4263 if (len != 0) {
4264 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004265 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004266 goto drop;
4267 }
4268
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004269 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004270 }
4271
4272 return 0;
4273
4274drop:
4275 kfree_skb(skb);
4276 return 0;
4277}
4278
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4280{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004281 struct l2cap_chan *chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004282 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004283 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004284 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004286 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004287 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 BT_DBG("unknown cid 0x%4.4x", cid);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004289 /* Drop packet and return */
4290 kfree(skb);
4291 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 }
4293
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004294 l2cap_chan_lock(chan);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004295
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004296 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004298 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299 goto drop;
4300
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004301 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004302 case L2CAP_MODE_BASIC:
4303 /* If socket recv buffers overflows we drop data here
4304 * which is *bad* because L2CAP has to be reliable.
4305 * But we don't have any other choice. L2CAP doesn't
4306 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004308 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004309 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004311 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004312 goto done;
4313 break;
4314
4315 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004316 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004317
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004318 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004319
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004320 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004321 control = __get_control(chan, skb->data);
4322 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004323 len = skb->len;
4324
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004325 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004326 goto drop;
4327
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004328 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004329 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004330
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004331 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004332 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004333
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004334 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004335 goto drop;
4336
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004337 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004338
Mat Martineau84084a32011-07-22 14:54:00 -07004339 if (chan->expected_tx_seq != tx_seq) {
4340 /* Frame(s) missing - must discard partial SDU */
4341 kfree_skb(chan->sdu);
4342 chan->sdu = NULL;
4343 chan->sdu_last_frag = NULL;
4344 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004345
Mat Martineau84084a32011-07-22 14:54:00 -07004346 /* TODO: Notify userland of missing data */
4347 }
4348
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004349 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004350
4351 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4352 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004353
4354 goto done;
4355
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004356 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004357 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004358 break;
4359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360
4361drop:
4362 kfree_skb(skb);
4363
4364done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004365 l2cap_chan_unlock(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +02004366
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 return 0;
4368}
4369
Al Viro8e036fc2007-07-29 00:16:36 -07004370static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004372 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004374 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4375 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 goto drop;
4377
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004378 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004380 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 goto drop;
4382
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004383 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 goto drop;
4385
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004386 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004387 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388
4389drop:
4390 kfree_skb(skb);
4391
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 return 0;
4393}
4394
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004395static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4396{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004397 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004398
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004399 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4400 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004401 goto drop;
4402
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004403 BT_DBG("chan %p, len %d", chan, skb->len);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004404
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004405 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004406 goto drop;
4407
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004408 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004409 goto drop;
4410
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004411 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004412 return 0;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004413
4414drop:
4415 kfree_skb(skb);
4416
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004417 return 0;
4418}
4419
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4421{
4422 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004423 u16 cid, len;
4424 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425
4426 skb_pull(skb, L2CAP_HDR_SIZE);
4427 cid = __le16_to_cpu(lh->cid);
4428 len = __le16_to_cpu(lh->len);
4429
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004430 if (len != skb->len) {
4431 kfree_skb(skb);
4432 return;
4433 }
4434
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4436
4437 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004438 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004439 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 l2cap_sig_channel(conn, skb);
4441 break;
4442
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004443 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004444 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 skb_pull(skb, 2);
4446 l2cap_conless_channel(conn, psm, skb);
4447 break;
4448
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004449 case L2CAP_CID_LE_DATA:
4450 l2cap_att_channel(conn, cid, skb);
4451 break;
4452
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004453 case L2CAP_CID_SMP:
4454 if (smp_sig_channel(conn, skb))
4455 l2cap_conn_del(conn->hcon, EACCES);
4456 break;
4457
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 default:
4459 l2cap_data_channel(conn, cid, skb);
4460 break;
4461 }
4462}
4463
4464/* ---- L2CAP interface with lower layer (HCI) ---- */
4465
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004466int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467{
4468 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004469 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4472
4473 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004474 read_lock(&chan_list_lock);
4475 list_for_each_entry(c, &chan_list, global_l) {
4476 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004477
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004478 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479 continue;
4480
4481 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004482 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004483 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004484 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004486 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4487 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004488 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004489 lm2 |= HCI_LM_MASTER;
4490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004492 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493
4494 return exact ? lm1 : lm2;
4495}
4496
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004497int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498{
Marcel Holtmann01394182006-07-03 10:02:46 +02004499 struct l2cap_conn *conn;
4500
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4502
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 conn = l2cap_conn_add(hcon, status);
4505 if (conn)
4506 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004507 } else
Joe Perchese1750722011-06-29 18:18:29 -07004508 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509
4510 return 0;
4511}
4512
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004513int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004514{
4515 struct l2cap_conn *conn = hcon->l2cap_data;
4516
4517 BT_DBG("hcon %p", hcon);
4518
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004519 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004520 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004521 return conn->disc_reason;
4522}
4523
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004524int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525{
4526 BT_DBG("hcon %p reason %d", hcon, reason);
4527
Joe Perchese1750722011-06-29 18:18:29 -07004528 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529 return 0;
4530}
4531
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004532static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004533{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004534 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004535 return;
4536
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004537 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004538 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004539 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004540 __set_chan_timer(chan,
4541 msecs_to_jiffies(L2CAP_ENC_TIMEOUT));
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004542 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004543 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004544 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004545 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004546 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004547 }
4548}
4549
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004550int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004552 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004553 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554
Marcel Holtmann01394182006-07-03 10:02:46 +02004555 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004557
Linus Torvalds1da177e2005-04-16 15:20:36 -07004558 BT_DBG("conn %p", conn);
4559
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004560 if (hcon->type == LE_LINK) {
4561 smp_distribute_keys(conn, 0);
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02004562 cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004563 }
4564
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004565 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004567 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004568 l2cap_chan_lock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004570 BT_DBG("chan->scid %d", chan->scid);
4571
4572 if (chan->scid == L2CAP_CID_LE_DATA) {
4573 if (!status && encrypt) {
4574 chan->sec_level = hcon->sec_level;
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02004575 l2cap_chan_ready(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004576 }
4577
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004578 l2cap_chan_unlock(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004579 continue;
4580 }
4581
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004582 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004583 l2cap_chan_unlock(chan);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004584 continue;
4585 }
4586
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004587 if (!status && (chan->state == BT_CONNECTED ||
4588 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004589 l2cap_check_encryption(chan, encrypt);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004590 l2cap_chan_unlock(chan);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004591 continue;
4592 }
4593
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004594 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004595 if (!status) {
4596 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004597 req.scid = cpu_to_le16(chan->scid);
4598 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004599
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004600 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004601 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004602
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004603 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004604 L2CAP_CONN_REQ, sizeof(req), &req);
4605 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004606 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004607 __set_chan_timer(chan,
4608 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004609 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004610 } else if (chan->state == BT_CONNECT2) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004611 struct sock *sk = chan->sk;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004612 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004613 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004614
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004615 lock_sock(sk);
4616
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004617 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004618 if (bt_sk(sk)->defer_setup) {
4619 struct sock *parent = bt_sk(sk)->parent;
4620 res = L2CAP_CR_PEND;
4621 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004622 if (parent)
4623 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004624 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004625 __l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004626 res = L2CAP_CR_SUCCESS;
4627 stat = L2CAP_CS_NO_INFO;
4628 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004629 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004630 __l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004631 __set_chan_timer(chan,
4632 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004633 res = L2CAP_CR_SEC_BLOCK;
4634 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004635 }
4636
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004637 release_sock(sk);
4638
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004639 rsp.scid = cpu_to_le16(chan->dcid);
4640 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004641 rsp.result = cpu_to_le16(res);
4642 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004643 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4644 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 }
4646
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004647 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 }
4649
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004650 mutex_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004651
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 return 0;
4653}
4654
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004655int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656{
4657 struct l2cap_conn *conn = hcon->l2cap_data;
4658
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004659 if (!conn)
4660 conn = l2cap_conn_add(hcon, 0);
4661
4662 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 goto drop;
4664
4665 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4666
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004667 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004669 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004670 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 int len;
4672
4673 if (conn->rx_len) {
4674 BT_ERR("Unexpected start frame (len %d)", skb->len);
4675 kfree_skb(conn->rx_skb);
4676 conn->rx_skb = NULL;
4677 conn->rx_len = 0;
4678 l2cap_conn_unreliable(conn, ECOMM);
4679 }
4680
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004681 /* Start fragment always begin with Basic L2CAP header */
4682 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004683 BT_ERR("Frame is too short (len %d)", skb->len);
4684 l2cap_conn_unreliable(conn, ECOMM);
4685 goto drop;
4686 }
4687
4688 hdr = (struct l2cap_hdr *) skb->data;
4689 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004690 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691
4692 if (len == skb->len) {
4693 /* Complete frame received */
4694 l2cap_recv_frame(conn, skb);
4695 return 0;
4696 }
4697
4698 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4699
4700 if (skb->len > len) {
4701 BT_ERR("Frame is too long (len %d, expected len %d)",
4702 skb->len, len);
4703 l2cap_conn_unreliable(conn, ECOMM);
4704 goto drop;
4705 }
4706
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004707 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004708
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004709 if (chan && chan->sk) {
4710 struct sock *sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004711 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004712
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004713 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004714 BT_ERR("Frame exceeding recv MTU (len %d, "
4715 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004716 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004717 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004718 l2cap_conn_unreliable(conn, ECOMM);
4719 goto drop;
4720 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004721 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004722 }
4723
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004725 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4726 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 goto drop;
4728
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004729 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004730 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 conn->rx_len = len - skb->len;
4732 } else {
4733 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4734
4735 if (!conn->rx_len) {
4736 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4737 l2cap_conn_unreliable(conn, ECOMM);
4738 goto drop;
4739 }
4740
4741 if (skb->len > conn->rx_len) {
4742 BT_ERR("Fragment is too long (len %d, expected %d)",
4743 skb->len, conn->rx_len);
4744 kfree_skb(conn->rx_skb);
4745 conn->rx_skb = NULL;
4746 conn->rx_len = 0;
4747 l2cap_conn_unreliable(conn, ECOMM);
4748 goto drop;
4749 }
4750
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004751 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004752 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753 conn->rx_len -= skb->len;
4754
4755 if (!conn->rx_len) {
4756 /* Complete frame received */
4757 l2cap_recv_frame(conn, conn->rx_skb);
4758 conn->rx_skb = NULL;
4759 }
4760 }
4761
4762drop:
4763 kfree_skb(skb);
4764 return 0;
4765}
4766
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004767static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004769 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004771 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004773 list_for_each_entry(c, &chan_list, global_l) {
4774 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004776 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 +01004777 batostr(&bt_sk(sk)->src),
4778 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004779 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004780 c->scid, c->dcid, c->imtu, c->omtu,
4781 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004782 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004783
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004784 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004785
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004786 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787}
4788
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004789static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4790{
4791 return single_open(file, l2cap_debugfs_show, inode->i_private);
4792}
4793
4794static const struct file_operations l2cap_debugfs_fops = {
4795 .open = l2cap_debugfs_open,
4796 .read = seq_read,
4797 .llseek = seq_lseek,
4798 .release = single_release,
4799};
4800
4801static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004803int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804{
4805 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004806
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004807 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 if (err < 0)
4809 return err;
4810
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004811 if (bt_debugfs) {
4812 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4813 bt_debugfs, NULL, &l2cap_debugfs_fops);
4814 if (!l2cap_debugfs)
4815 BT_ERR("Failed to create L2CAP debug file");
4816 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819}
4820
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004821void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004823 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004824 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004825}
4826
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004827module_param(disable_ertm, bool, 0644);
4828MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");