blob: 0e4f4cb2acbba035e71d710e074d59c9a044378f [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. Padovan710f9b0a2011-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 struct sock *sk = chan->sk;
242 int reason;
243
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200244 BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300245
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200246 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300247 lock_sock(sk);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300248
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300249 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300250 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300251 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300252 chan->sec_level != BT_SECURITY_SDP)
253 reason = ECONNREFUSED;
254 else
255 reason = ETIMEDOUT;
256
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300257 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300258
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300259 release_sock(sk);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300260
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300261 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200262 mutex_unlock(&conn->chan_lock);
263
Ulisses Furquim371fd832011-12-21 20:02:36 -0200264 l2cap_chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300265}
266
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300267struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200268{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300269 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200270
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300271 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
272 if (!chan)
273 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200274
Andrei Emeltchenkoc03b3552012-02-21 12:54:56 +0200275 mutex_init(&chan->lock);
276
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300277 chan->sk = sk;
278
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200279 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300280 list_add(&chan->global_l, &chan_list);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200281 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300282
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300283 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300284
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300285 chan->state = BT_OPEN;
286
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300287 atomic_set(&chan->refcnt, 1);
288
Szymon Jancabc545b2011-11-03 16:05:44 +0100289 BT_DBG("sk %p chan %p", sk, chan);
290
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300291 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200292}
293
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300294void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300295{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200296 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300297 list_del(&chan->global_l);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200298 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300299
Ulisses Furquim371fd832011-12-21 20:02:36 -0200300 l2cap_chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300301}
302
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200303void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200304{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300305 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300306 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200307
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200308 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100309
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300310 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200311
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200312 switch (chan->chan_type) {
313 case L2CAP_CHAN_CONN_ORIENTED:
Ville Tervob62f3282011-02-10 22:38:50 -0300314 if (conn->hcon->type == LE_LINK) {
315 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300316 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300317 chan->scid = L2CAP_CID_LE_DATA;
318 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300319 } else {
320 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300321 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300322 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300323 }
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200324 break;
325
326 case L2CAP_CHAN_CONN_LESS:
Marcel Holtmann01394182006-07-03 10:02:46 +0200327 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300328 chan->scid = L2CAP_CID_CONN_LESS;
329 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300330 chan->omtu = L2CAP_DEFAULT_MTU;
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200331 break;
332
333 default:
Marcel Holtmann01394182006-07-03 10:02:46 +0200334 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300335 chan->scid = L2CAP_CID_SIGNALING;
336 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300337 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200338 }
339
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300340 chan->local_id = L2CAP_BESTEFFORT_ID;
341 chan->local_stype = L2CAP_SERV_BESTEFFORT;
342 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
343 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
344 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
345 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
346
Ulisses Furquim371fd832011-12-21 20:02:36 -0200347 l2cap_chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300348
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200349 list_add(&chan->list, &conn->chan_l);
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200350}
351
352void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
353{
354 mutex_lock(&conn->chan_lock);
355 __l2cap_chan_add(conn, chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200356 mutex_unlock(&conn->chan_lock);
Marcel Holtmann01394182006-07-03 10:02:46 +0200357}
358
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900359/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200360 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300361static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200362{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300363 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300364 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200365 struct sock *parent = bt_sk(sk)->parent;
366
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300367 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200368
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300369 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200370
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900371 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300372 /* Delete from channel list */
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200373 list_del(&chan->list);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200374
Ulisses Furquim371fd832011-12-21 20:02:36 -0200375 l2cap_chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300376
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300377 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200378 hci_conn_put(conn->hcon);
379 }
380
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200381 __l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200382 sock_set_flag(sk, SOCK_ZAPPED);
383
384 if (err)
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200385 __l2cap_chan_set_err(chan, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200386
387 if (parent) {
388 bt_accept_unlink(sk);
389 parent->sk_data_ready(parent, 0);
390 } else
391 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300392
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300393 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
394 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300395 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300396
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300397 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300398
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300399 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300400 struct srej_list *l, *tmp;
401
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300402 __clear_retrans_timer(chan);
403 __clear_monitor_timer(chan);
404 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300405
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300406 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300407
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300408 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300409 list_del(&l->list);
410 kfree(l);
411 }
412 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200413}
414
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300415static void l2cap_chan_cleanup_listen(struct sock *parent)
416{
417 struct sock *sk;
418
419 BT_DBG("parent %p", parent);
420
421 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300422 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300423 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200424
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300425 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300426 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300427 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300428 release_sock(sk);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200429
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300430 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300431 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300432}
433
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300434void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300435{
436 struct l2cap_conn *conn = chan->conn;
437 struct sock *sk = chan->sk;
438
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200439 BT_DBG("chan %p state %s sk %p", chan,
440 state_to_string(chan->state), sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300441
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300442 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300443 case BT_LISTEN:
444 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300445
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200446 __l2cap_state_change(chan, BT_CLOSED);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300447 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300448 break;
449
450 case BT_CONNECTED:
451 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300452 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300453 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300454 __clear_chan_timer(chan);
455 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300456 l2cap_send_disconn_req(conn, chan, reason);
457 } else
458 l2cap_chan_del(chan, reason);
459 break;
460
461 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300462 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300463 conn->hcon->type == ACL_LINK) {
464 struct l2cap_conn_rsp rsp;
465 __u16 result;
466
467 if (bt_sk(sk)->defer_setup)
468 result = L2CAP_CR_SEC_BLOCK;
469 else
470 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300471 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300472
473 rsp.scid = cpu_to_le16(chan->dcid);
474 rsp.dcid = cpu_to_le16(chan->scid);
475 rsp.result = cpu_to_le16(result);
476 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
477 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
478 sizeof(rsp), &rsp);
479 }
480
481 l2cap_chan_del(chan, reason);
482 break;
483
484 case BT_CONNECT:
485 case BT_DISCONN:
486 l2cap_chan_del(chan, reason);
487 break;
488
489 default:
490 sock_set_flag(sk, SOCK_ZAPPED);
491 break;
492 }
493}
494
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300495static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530496{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300497 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300498 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530499 case BT_SECURITY_HIGH:
500 return HCI_AT_DEDICATED_BONDING_MITM;
501 case BT_SECURITY_MEDIUM:
502 return HCI_AT_DEDICATED_BONDING;
503 default:
504 return HCI_AT_NO_BONDING;
505 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300506 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300507 if (chan->sec_level == BT_SECURITY_LOW)
508 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530509
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300510 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530511 return HCI_AT_NO_BONDING_MITM;
512 else
513 return HCI_AT_NO_BONDING;
514 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300515 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530516 case BT_SECURITY_HIGH:
517 return HCI_AT_GENERAL_BONDING_MITM;
518 case BT_SECURITY_MEDIUM:
519 return HCI_AT_GENERAL_BONDING;
520 default:
521 return HCI_AT_NO_BONDING;
522 }
523 }
524}
525
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200526/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200527int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200528{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300529 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100530 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200531
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300532 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100533
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300534 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200535}
536
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200537static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200538{
539 u8 id;
540
541 /* Get next available identificator.
542 * 1 - 128 are used by kernel.
543 * 129 - 199 are reserved.
544 * 200 - 254 are used by utilities like l2ping, etc.
545 */
546
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200547 spin_lock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200548
549 if (++conn->tx_ident > 128)
550 conn->tx_ident = 1;
551
552 id = conn->tx_ident;
553
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200554 spin_unlock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200555
556 return id;
557}
558
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300559static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200560{
561 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200562 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200563
564 BT_DBG("code 0x%2.2x", code);
565
566 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300567 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200568
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200569 if (lmp_no_flush_capable(conn->hcon->hdev))
570 flags = ACL_START_NO_FLUSH;
571 else
572 flags = ACL_START;
573
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700574 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200575 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700576
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200577 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200578}
579
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200580static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
581{
582 struct hci_conn *hcon = chan->conn->hcon;
583 u16 flags;
584
585 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
586 skb->priority);
587
588 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
589 lmp_no_flush_capable(hcon->hdev))
590 flags = ACL_START_NO_FLUSH;
591 else
592 flags = ACL_START;
593
594 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
595 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596}
597
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300598static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300599{
600 struct sk_buff *skb;
601 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300602 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300603 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300604
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300605 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300606 return;
607
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300608 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
609 hlen = L2CAP_EXT_HDR_SIZE;
610 else
611 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300612
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300613 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300614 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300615
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300616 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300617
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300618 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300619
620 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300621
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300622 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300623 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300624
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300625 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300626 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300627
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300628 skb = bt_skb_alloc(count, GFP_ATOMIC);
629 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300630 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300631
632 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300633 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300634 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300635
636 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300637
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300638 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300639 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
640 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300641 }
642
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200643 skb->priority = HCI_PRIO_MAX;
644 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300645}
646
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300647static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300648{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300649 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300650 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300651 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300652 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300653 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300654
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300655 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300656
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300657 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300658}
659
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300660static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300661{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300662 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300663}
664
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300665static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200666{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300667 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200668
669 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100670 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
671 return;
672
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200673 if (l2cap_chan_check_security(chan) &&
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300674 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200675 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300676 req.scid = cpu_to_le16(chan->scid);
677 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200678
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300679 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300680 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200681
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300682 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
683 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200684 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200685 } else {
686 struct l2cap_info_req req;
687 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
688
689 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
690 conn->info_ident = l2cap_get_ident(conn);
691
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200692 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200693 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
694
695 l2cap_send_cmd(conn, conn->info_ident,
696 L2CAP_INFO_REQ, sizeof(req), &req);
697 }
698}
699
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300700static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
701{
702 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300703 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300704 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
705
706 switch (mode) {
707 case L2CAP_MODE_ERTM:
708 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
709 case L2CAP_MODE_STREAMING:
710 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
711 default:
712 return 0x00;
713 }
714}
715
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300716static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300717{
718 struct l2cap_disconn_req req;
719
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300720 if (!conn)
721 return;
722
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300723 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300724 __clear_retrans_timer(chan);
725 __clear_monitor_timer(chan);
726 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300727 }
728
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300729 req.dcid = cpu_to_le16(chan->dcid);
730 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300731 l2cap_send_cmd(conn, l2cap_get_ident(conn),
732 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300733
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200734 __l2cap_state_change(chan, BT_DISCONN);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200735 __l2cap_chan_set_err(chan, err);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300736}
737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200739static void l2cap_conn_start(struct l2cap_conn *conn)
740{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200741 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200742
743 BT_DBG("conn %p", conn);
744
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200745 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200746
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200747 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300748 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300749
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200750 bh_lock_sock(sk);
751
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300752 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200753 bh_unlock_sock(sk);
754 continue;
755 }
756
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300757 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300758 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300759
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200760 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300761 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300762 bh_unlock_sock(sk);
763 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200764 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300765
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300766 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
767 && test_bit(CONF_STATE2_DEVICE,
768 &chan->conf_state)) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300769 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300770 * so release the lock */
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300771 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300772 bh_unlock_sock(sk);
773 continue;
774 }
775
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300776 req.scid = cpu_to_le16(chan->scid);
777 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300778
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300779 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300780 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300781
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300782 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
783 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300784
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300785 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200786 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300787 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300788 rsp.scid = cpu_to_le16(chan->dcid);
789 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200790
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200791 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100792 if (bt_sk(sk)->defer_setup) {
793 struct sock *parent = bt_sk(sk)->parent;
794 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
795 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000796 if (parent)
797 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100798
799 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200800 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100801 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
802 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
803 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200804 } else {
805 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
806 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
807 }
808
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300809 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
810 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300811
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300812 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300813 rsp.result != L2CAP_CR_SUCCESS) {
814 bh_unlock_sock(sk);
815 continue;
816 }
817
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300818 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300819 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300820 l2cap_build_conf_req(chan, buf), buf);
821 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200822 }
823
824 bh_unlock_sock(sk);
825 }
826
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200827 mutex_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200828}
829
Ville Tervob62f3282011-02-10 22:38:50 -0300830/* Find socket with cid and source bdaddr.
831 * Returns closest match, locked.
832 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300833static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300834{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300835 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300836
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300837 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300838
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300839 list_for_each_entry(c, &chan_list, global_l) {
840 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300841
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300842 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300843 continue;
844
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300845 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300846 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300847 if (!bacmp(&bt_sk(sk)->src, src)) {
848 read_unlock(&chan_list_lock);
849 return c;
850 }
Ville Tervob62f3282011-02-10 22:38:50 -0300851
852 /* Closest match */
853 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300854 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300855 }
856 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300857
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300858 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300859
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300860 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300861}
862
863static void l2cap_le_conn_ready(struct l2cap_conn *conn)
864{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300865 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300866 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300867
868 BT_DBG("");
869
870 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300871 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300872 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300873 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300874 return;
875
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300876 parent = pchan->sk;
877
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300878 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300879
Ville Tervob62f3282011-02-10 22:38:50 -0300880 /* Check for backlog size */
881 if (sk_acceptq_is_full(parent)) {
882 BT_DBG("backlog full %d", parent->sk_ack_backlog);
883 goto clean;
884 }
885
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300886 chan = pchan->ops->new_connection(pchan->data);
887 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300888 goto clean;
889
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300890 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300891
Ville Tervob62f3282011-02-10 22:38:50 -0300892 hci_conn_hold(conn->hcon);
893
Ville Tervob62f3282011-02-10 22:38:50 -0300894 bacpy(&bt_sk(sk)->src, conn->src);
895 bacpy(&bt_sk(sk)->dst, conn->dst);
896
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300897 bt_accept_enqueue(parent, sk);
898
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200899 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300900
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300901 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300902
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200903 __l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300904 parent->sk_data_ready(parent, 0);
905
Ville Tervob62f3282011-02-10 22:38:50 -0300906clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300907 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300908}
909
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200910static void l2cap_chan_ready(struct l2cap_chan *chan)
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300911{
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200912 struct sock *sk = chan->sk;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300913 struct sock *parent = bt_sk(sk)->parent;
914
915 BT_DBG("sk %p, parent %p", sk, parent);
916
917 chan->conf_state = 0;
918 __clear_chan_timer(chan);
919
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200920 __l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300921 sk->sk_state_change(sk);
922
923 if (parent)
924 parent->sk_data_ready(parent, 0);
925}
926
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200927static void l2cap_conn_ready(struct l2cap_conn *conn)
928{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300929 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200930
931 BT_DBG("conn %p", conn);
932
Ville Tervob62f3282011-02-10 22:38:50 -0300933 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
934 l2cap_le_conn_ready(conn);
935
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300936 if (conn->hcon->out && conn->hcon->type == LE_LINK)
937 smp_conn_security(conn, conn->hcon->pending_sec_level);
938
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200939 mutex_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200940
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200941 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300942 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300943
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200944 bh_lock_sock(sk);
945
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300946 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300947 if (smp_conn_security(conn, chan->sec_level))
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200948 l2cap_chan_ready(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300949
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300950 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300951 __clear_chan_timer(chan);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200952 __l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200953 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300954
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300955 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300956 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200957
958 bh_unlock_sock(sk);
959 }
960
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200961 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200962}
963
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200964/* Notify sockets that we cannot guaranty reliability anymore */
965static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
966{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300967 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200968
969 BT_DBG("conn %p", conn);
970
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200971 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200972
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200973 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300974 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200975 __l2cap_chan_set_err(chan, err);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200976 }
977
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200978 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200979}
980
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200981static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200982{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200983 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200984 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200985
Marcel Holtmann984947d2009-02-06 23:35:19 +0100986 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100987 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100988
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200989 l2cap_conn_start(conn);
990}
991
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300992static void l2cap_conn_del(struct hci_conn *hcon, int err)
993{
994 struct l2cap_conn *conn = hcon->l2cap_data;
995 struct l2cap_chan *chan, *l;
996 struct sock *sk;
997
998 if (!conn)
999 return;
1000
1001 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1002
1003 kfree_skb(conn->rx_skb);
1004
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001005 mutex_lock(&conn->chan_lock);
1006
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001007 /* Kill channels */
1008 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
1009 sk = chan->sk;
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03001010 lock_sock(sk);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001011 l2cap_chan_del(chan, err);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03001012 release_sock(sk);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001013 chan->ops->close(chan->data);
1014 }
1015
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001016 mutex_unlock(&conn->chan_lock);
1017
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001018 hci_chan_del(conn->hchan);
1019
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001020 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim127074b2012-01-30 18:26:29 -02001021 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001022
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001023 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim127074b2012-01-30 18:26:29 -02001024 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001025 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001026 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001027
1028 hcon->l2cap_data = NULL;
1029 kfree(conn);
1030}
1031
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001032static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001033{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001034 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1035 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001036
1037 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1038}
1039
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1041{
Marcel Holtmann01394182006-07-03 10:02:46 +02001042 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001043 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Marcel Holtmann01394182006-07-03 10:02:46 +02001045 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return conn;
1047
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001048 hchan = hci_chan_create(hcon);
1049 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001052 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1053 if (!conn) {
1054 hci_chan_del(hchan);
1055 return NULL;
1056 }
1057
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 hcon->l2cap_data = conn;
1059 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001060 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001062 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001063
Ville Tervoacd7d372011-02-10 22:38:49 -03001064 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1065 conn->mtu = hcon->hdev->le_mtu;
1066 else
1067 conn->mtu = hcon->hdev->acl_mtu;
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 conn->src = &hcon->hdev->bdaddr;
1070 conn->dst = &hcon->dst;
1071
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001072 conn->feat_mask = 0;
1073
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 spin_lock_init(&conn->lock);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001075 mutex_init(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001076
1077 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001079 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001080 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001081 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001082 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001083
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001084 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001085
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 return conn;
1087}
1088
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
1091/* Find socket with psm and source bdaddr.
1092 * Returns closest match.
1093 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001094static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001096 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001098 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001099
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001100 list_for_each_entry(c, &chan_list, global_l) {
1101 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001102
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001103 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 continue;
1105
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001106 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001108 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001109 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001110 return c;
1111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113 /* Closest match */
1114 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001115 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 }
1117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001119 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001120
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001121 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122}
1123
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001124int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001126 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 struct l2cap_conn *conn;
1129 struct hci_conn *hcon;
1130 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001131 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001132 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001134 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001135 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001137 hdev = hci_get_route(dst, src);
1138 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 return -EHOSTUNREACH;
1140
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001141 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001143 lock_sock(sk);
1144
1145 /* PSM must be odd and lsb of upper byte must be 0 */
1146 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1147 chan->chan_type != L2CAP_CHAN_RAW) {
1148 err = -EINVAL;
1149 goto done;
1150 }
1151
1152 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1153 err = -EINVAL;
1154 goto done;
1155 }
1156
1157 switch (chan->mode) {
1158 case L2CAP_MODE_BASIC:
1159 break;
1160 case L2CAP_MODE_ERTM:
1161 case L2CAP_MODE_STREAMING:
1162 if (!disable_ertm)
1163 break;
1164 /* fall through */
1165 default:
1166 err = -ENOTSUPP;
1167 goto done;
1168 }
1169
1170 switch (sk->sk_state) {
1171 case BT_CONNECT:
1172 case BT_CONNECT2:
1173 case BT_CONFIG:
1174 /* Already connecting */
1175 err = 0;
1176 goto done;
1177
1178 case BT_CONNECTED:
1179 /* Already connected */
1180 err = -EISCONN;
1181 goto done;
1182
1183 case BT_OPEN:
1184 case BT_BOUND:
1185 /* Can connect */
1186 break;
1187
1188 default:
1189 err = -EBADFD;
1190 goto done;
1191 }
1192
1193 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001194 bacpy(&bt_sk(sk)->dst, dst);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001195 chan->psm = psm;
1196 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001198 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001199
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001200 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001201 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001202 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001203 else
1204 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001205 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001206
Ville Tervo30e76272011-02-22 16:10:53 -03001207 if (IS_ERR(hcon)) {
1208 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
1212 conn = l2cap_conn_add(hcon, 0);
1213 if (!conn) {
1214 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001215 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 goto done;
1217 }
1218
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 /* Update source addr of the socket */
1220 bacpy(src, conn->src);
1221
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001222 l2cap_chan_add(conn, chan);
1223
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02001224 __l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001225 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001228 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001229 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001230 if (l2cap_chan_check_security(chan))
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02001231 __l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001232 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001233 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 }
1235
Ville Tervo30e76272011-02-22 16:10:53 -03001236 err = 0;
1237
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001239 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 hci_dev_put(hdev);
1241 return err;
1242}
1243
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001244int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001245{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001246 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001247 DECLARE_WAITQUEUE(wait, current);
1248 int err = 0;
1249 int timeo = HZ/5;
1250
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001251 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001252 set_current_state(TASK_INTERRUPTIBLE);
1253 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001254 if (!timeo)
1255 timeo = HZ/5;
1256
1257 if (signal_pending(current)) {
1258 err = sock_intr_errno(timeo);
1259 break;
1260 }
1261
1262 release_sock(sk);
1263 timeo = schedule_timeout(timeo);
1264 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001265 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001266
1267 err = sock_error(sk);
1268 if (err)
1269 break;
1270 }
1271 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001272 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001273 return err;
1274}
1275
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001276static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001277{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001278 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1279 monitor_timer.work);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001280 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001281
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001282 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001283
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001284 lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001285 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001286 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001287 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001288 return;
1289 }
1290
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001291 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001292 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001293
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001294 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001295 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001296}
1297
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001298static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001299{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001300 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1301 retrans_timer.work);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001302 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001303
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001304 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001305
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001306 lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001307 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001308 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001309
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001310 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001311
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001312 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001313 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001314}
1315
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001316static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001317{
1318 struct sk_buff *skb;
1319
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001320 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001321 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001322 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001323 break;
1324
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001325 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001326 kfree_skb(skb);
1327
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001328 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001329 }
1330
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001331 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001332 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001333}
1334
Szymon Janc67c9e842011-07-28 16:24:33 +02001335static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001336{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001337 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001338 u32 control;
1339 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001340
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001341 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001342 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001343 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001344 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001345
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001346 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001347 fcs = crc16(0, (u8 *)skb->data,
1348 skb->len - L2CAP_FCS_SIZE);
1349 put_unaligned_le16(fcs,
1350 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001351 }
1352
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001353 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001354
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001355 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001356 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001357}
1358
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001359static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001360{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001361 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001362 u16 fcs;
1363 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001364
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001365 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001366 if (!skb)
1367 return;
1368
Szymon Jancd1726b62011-11-16 09:32:20 +01001369 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001370 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001371 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001372
Szymon Jancd1726b62011-11-16 09:32:20 +01001373 skb = skb_queue_next(&chan->tx_q, skb);
1374 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001375
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001376 if (chan->remote_max_tx &&
1377 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001378 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001379 return;
1380 }
1381
1382 tx_skb = skb_clone(skb, GFP_ATOMIC);
1383 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001384
1385 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001386 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001387
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001388 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001389 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001390
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001391 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001392 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001393
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001394 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001395
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001396 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001397 fcs = crc16(0, (u8 *)tx_skb->data,
1398 tx_skb->len - L2CAP_FCS_SIZE);
1399 put_unaligned_le16(fcs,
1400 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001401 }
1402
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001403 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001404}
1405
Szymon Janc67c9e842011-07-28 16:24:33 +02001406static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001407{
1408 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001409 u16 fcs;
1410 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001411 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001412
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001413 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001414 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001415
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001416 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001417
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001418 if (chan->remote_max_tx &&
1419 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001420 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001421 break;
1422 }
1423
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001424 tx_skb = skb_clone(skb, GFP_ATOMIC);
1425
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001426 bt_cb(skb)->retries++;
1427
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001428 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001429 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001430
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001431 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001432 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001433
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001434 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001435 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001436
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001437 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001438
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001439 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001440 fcs = crc16(0, (u8 *)skb->data,
1441 tx_skb->len - L2CAP_FCS_SIZE);
1442 put_unaligned_le16(fcs, skb->data +
1443 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001444 }
1445
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001446 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001447
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001448 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001449
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001450 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001451
1452 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001453
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001454 if (bt_cb(skb)->retries == 1) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001455 chan->unacked_frames++;
Szymon Janc930fa4a2012-02-07 15:43:02 +01001456
1457 if (!nsent++)
1458 __clear_ack_timer(chan);
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001459 }
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301460
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001461 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001462
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001463 if (skb_queue_is_last(&chan->tx_q, skb))
1464 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001465 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001466 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001467 }
1468
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001469 return nsent;
1470}
1471
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001472static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001473{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001474 int ret;
1475
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001476 if (!skb_queue_empty(&chan->tx_q))
1477 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001478
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001479 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001480 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001481 return ret;
1482}
1483
Szymon Jancb17e73b2012-01-11 10:59:47 +01001484static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001485{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001486 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001487
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001488 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001489
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001490 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001491 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001492 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001493 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001494 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001495 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001496
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001497 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001498 return;
1499
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001500 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001501 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001502}
1503
Szymon Jancb17e73b2012-01-11 10:59:47 +01001504static void l2cap_send_ack(struct l2cap_chan *chan)
1505{
1506 __clear_ack_timer(chan);
1507 __l2cap_send_ack(chan);
1508}
1509
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001510static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001511{
1512 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001513 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001514
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001515 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001516 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001517
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001518 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001519 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001520
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001521 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001522}
1523
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001524static 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 -07001525{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001526 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001527 struct sk_buff **frag;
1528 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001530 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001531 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532
1533 sent += count;
1534 len -= count;
1535
1536 /* Continuation fragments (no L2CAP header) */
1537 frag = &skb_shinfo(skb)->frag_list;
1538 while (len) {
1539 count = min_t(unsigned int, conn->mtu, len);
1540
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001541 *frag = chan->ops->alloc_skb(chan, count,
1542 msg->msg_flags & MSG_DONTWAIT, &err);
1543
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001545 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001546 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1547 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001549 (*frag)->priority = skb->priority;
1550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 sent += count;
1552 len -= count;
1553
1554 frag = &(*frag)->next;
1555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
1557 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001558}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001560static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1561 struct msghdr *msg, size_t len,
1562 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001563{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001564 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001565 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001566 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001567 struct l2cap_hdr *lh;
1568
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001569 BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001570
1571 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001572
1573 skb = chan->ops->alloc_skb(chan, count + hlen,
1574 msg->msg_flags & MSG_DONTWAIT, &err);
1575
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001576 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001577 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001578
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001579 skb->priority = priority;
1580
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001581 /* Create L2CAP header */
1582 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001583 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001584 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001585 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001586
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001587 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001588 if (unlikely(err < 0)) {
1589 kfree_skb(skb);
1590 return ERR_PTR(err);
1591 }
1592 return skb;
1593}
1594
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001595static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1596 struct msghdr *msg, size_t len,
1597 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001598{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001599 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001600 struct sk_buff *skb;
1601 int err, count, hlen = L2CAP_HDR_SIZE;
1602 struct l2cap_hdr *lh;
1603
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001604 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001605
1606 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001607
1608 skb = chan->ops->alloc_skb(chan, count + hlen,
1609 msg->msg_flags & MSG_DONTWAIT, &err);
1610
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001611 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001612 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001613
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001614 skb->priority = priority;
1615
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001616 /* Create L2CAP header */
1617 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001618 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001619 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1620
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001621 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001622 if (unlikely(err < 0)) {
1623 kfree_skb(skb);
1624 return ERR_PTR(err);
1625 }
1626 return skb;
1627}
1628
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001629static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1630 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001631 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001632{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001633 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001634 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001635 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001636 struct l2cap_hdr *lh;
1637
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001638 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001639
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001640 if (!conn)
1641 return ERR_PTR(-ENOTCONN);
1642
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001643 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1644 hlen = L2CAP_EXT_HDR_SIZE;
1645 else
1646 hlen = L2CAP_ENH_HDR_SIZE;
1647
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001648 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001649 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001650
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001651 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001652 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001653
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001654 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001655
1656 skb = chan->ops->alloc_skb(chan, count + hlen,
1657 msg->msg_flags & MSG_DONTWAIT, &err);
1658
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001659 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001660 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001661
1662 /* Create L2CAP header */
1663 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001664 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001665 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001666
1667 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1668
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001669 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001670 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001671
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001672 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001673 if (unlikely(err < 0)) {
1674 kfree_skb(skb);
1675 return ERR_PTR(err);
1676 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001677
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001678 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001679 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001680
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001681 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001682 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683}
1684
Szymon Janc67c9e842011-07-28 16:24:33 +02001685static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001686{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001687 struct sk_buff *skb;
1688 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001689 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001690 size_t size = 0;
1691
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001692 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001693 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001694 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001695 if (IS_ERR(skb))
1696 return PTR_ERR(skb);
1697
1698 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001699 len -= chan->remote_mps;
1700 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001701
1702 while (len > 0) {
1703 size_t buflen;
1704
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001705 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001706 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001707 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001708 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001709 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001710 buflen = len;
1711 }
1712
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001713 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001714 if (IS_ERR(skb)) {
1715 skb_queue_purge(&sar_queue);
1716 return PTR_ERR(skb);
1717 }
1718
1719 __skb_queue_tail(&sar_queue, skb);
1720 len -= buflen;
1721 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001722 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001723 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1724 if (chan->tx_send_head == NULL)
1725 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001726
1727 return size;
1728}
1729
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001730int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1731 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001732{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001733 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001734 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001735 int err;
1736
1737 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001738 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001739 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001740 if (IS_ERR(skb))
1741 return PTR_ERR(skb);
1742
1743 l2cap_do_send(chan, skb);
1744 return len;
1745 }
1746
1747 switch (chan->mode) {
1748 case L2CAP_MODE_BASIC:
1749 /* Check outgoing MTU */
1750 if (len > chan->omtu)
1751 return -EMSGSIZE;
1752
1753 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001754 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001755 if (IS_ERR(skb))
1756 return PTR_ERR(skb);
1757
1758 l2cap_do_send(chan, skb);
1759 err = len;
1760 break;
1761
1762 case L2CAP_MODE_ERTM:
1763 case L2CAP_MODE_STREAMING:
1764 /* Entire SDU fits into one PDU */
1765 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001766 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001767 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1768 0);
1769 if (IS_ERR(skb))
1770 return PTR_ERR(skb);
1771
1772 __skb_queue_tail(&chan->tx_q, skb);
1773
1774 if (chan->tx_send_head == NULL)
1775 chan->tx_send_head = skb;
1776
1777 } else {
1778 /* Segment SDU into multiples PDUs */
1779 err = l2cap_sar_segment_sdu(chan, msg, len);
1780 if (err < 0)
1781 return err;
1782 }
1783
1784 if (chan->mode == L2CAP_MODE_STREAMING) {
1785 l2cap_streaming_send(chan);
1786 err = len;
1787 break;
1788 }
1789
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001790 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1791 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001792 err = len;
1793 break;
1794 }
1795
1796 err = l2cap_ertm_send(chan);
1797 if (err >= 0)
1798 err = len;
1799
1800 break;
1801
1802 default:
1803 BT_DBG("bad state %1.1x", chan->mode);
1804 err = -EBADFD;
1805 }
1806
1807 return err;
1808}
1809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810/* Copy frame to all raw sockets on that connection */
1811static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1812{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001814 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
1816 BT_DBG("conn %p", conn);
1817
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001818 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001819
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001820 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001821 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001822 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 continue;
1824
1825 /* Don't send frame to the socket it came from */
1826 if (skb->sk == sk)
1827 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001828 nskb = skb_clone(skb, GFP_ATOMIC);
1829 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 continue;
1831
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001832 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 kfree_skb(nskb);
1834 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001835
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001836 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837}
1838
1839/* ---- L2CAP signalling commands ---- */
1840static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1841 u8 code, u8 ident, u16 dlen, void *data)
1842{
1843 struct sk_buff *skb, **frag;
1844 struct l2cap_cmd_hdr *cmd;
1845 struct l2cap_hdr *lh;
1846 int len, count;
1847
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001848 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1849 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1852 count = min_t(unsigned int, conn->mtu, len);
1853
1854 skb = bt_skb_alloc(count, GFP_ATOMIC);
1855 if (!skb)
1856 return NULL;
1857
1858 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001859 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001860
1861 if (conn->hcon->type == LE_LINK)
1862 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1863 else
1864 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
1866 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1867 cmd->code = code;
1868 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001869 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871 if (dlen) {
1872 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1873 memcpy(skb_put(skb, count), data, count);
1874 data += count;
1875 }
1876
1877 len -= skb->len;
1878
1879 /* Continuation fragments (no L2CAP header) */
1880 frag = &skb_shinfo(skb)->frag_list;
1881 while (len) {
1882 count = min_t(unsigned int, conn->mtu, len);
1883
1884 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1885 if (!*frag)
1886 goto fail;
1887
1888 memcpy(skb_put(*frag, count), data, count);
1889
1890 len -= count;
1891 data += count;
1892
1893 frag = &(*frag)->next;
1894 }
1895
1896 return skb;
1897
1898fail:
1899 kfree_skb(skb);
1900 return NULL;
1901}
1902
1903static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1904{
1905 struct l2cap_conf_opt *opt = *ptr;
1906 int len;
1907
1908 len = L2CAP_CONF_OPT_SIZE + opt->len;
1909 *ptr += len;
1910
1911 *type = opt->type;
1912 *olen = opt->len;
1913
1914 switch (opt->len) {
1915 case 1:
1916 *val = *((u8 *) opt->val);
1917 break;
1918
1919 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001920 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 break;
1922
1923 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001924 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 break;
1926
1927 default:
1928 *val = (unsigned long) opt->val;
1929 break;
1930 }
1931
1932 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1933 return len;
1934}
1935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1937{
1938 struct l2cap_conf_opt *opt = *ptr;
1939
1940 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1941
1942 opt->type = type;
1943 opt->len = len;
1944
1945 switch (len) {
1946 case 1:
1947 *((u8 *) opt->val) = val;
1948 break;
1949
1950 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001951 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 break;
1953
1954 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001955 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 break;
1957
1958 default:
1959 memcpy(opt->val, (void *) val, len);
1960 break;
1961 }
1962
1963 *ptr += L2CAP_CONF_OPT_SIZE + len;
1964}
1965
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001966static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1967{
1968 struct l2cap_conf_efs efs;
1969
Szymon Janc1ec918c2011-11-16 09:32:21 +01001970 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001971 case L2CAP_MODE_ERTM:
1972 efs.id = chan->local_id;
1973 efs.stype = chan->local_stype;
1974 efs.msdu = cpu_to_le16(chan->local_msdu);
1975 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1976 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1977 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1978 break;
1979
1980 case L2CAP_MODE_STREAMING:
1981 efs.id = 1;
1982 efs.stype = L2CAP_SERV_BESTEFFORT;
1983 efs.msdu = cpu_to_le16(chan->local_msdu);
1984 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1985 efs.acc_lat = 0;
1986 efs.flush_to = 0;
1987 break;
1988
1989 default:
1990 return;
1991 }
1992
1993 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
1994 (unsigned long) &efs);
1995}
1996
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001997static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001998{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001999 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2000 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002001
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02002002 BT_DBG("chan %p", chan);
2003
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002004 lock_sock(chan->sk);
Szymon Jancb17e73b2012-01-11 10:59:47 +01002005 __l2cap_send_ack(chan);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002006 release_sock(chan->sk);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002007
2008 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002009}
2010
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002011static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002012{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002013 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002014 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002015 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002016 chan->num_acked = 0;
2017 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002018
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002019 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2020 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2021 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002022
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002023 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002024
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002025 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002026}
2027
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002028static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2029{
2030 switch (mode) {
2031 case L2CAP_MODE_STREAMING:
2032 case L2CAP_MODE_ERTM:
2033 if (l2cap_mode_supported(mode, remote_feat_mask))
2034 return mode;
2035 /* fall through */
2036 default:
2037 return L2CAP_MODE_BASIC;
2038 }
2039}
2040
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002041static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2042{
2043 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2044}
2045
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002046static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2047{
2048 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2049}
2050
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002051static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2052{
2053 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002054 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002055 /* use extended control field */
2056 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002057 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2058 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002059 chan->tx_win = min_t(u16, chan->tx_win,
2060 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002061 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2062 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002063}
2064
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002065static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002068 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002070 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002072 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002074 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002075 goto done;
2076
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002077 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002078 case L2CAP_MODE_STREAMING:
2079 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002080 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002081 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002082
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002083 if (__l2cap_efs_supported(chan))
2084 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2085
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002086 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002087 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002088 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002089 break;
2090 }
2091
2092done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002093 if (chan->imtu != L2CAP_DEFAULT_MTU)
2094 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002095
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002096 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002097 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002098 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2099 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002100 break;
2101
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002102 rfc.mode = L2CAP_MODE_BASIC;
2103 rfc.txwin_size = 0;
2104 rfc.max_transmit = 0;
2105 rfc.retrans_timeout = 0;
2106 rfc.monitor_timeout = 0;
2107 rfc.max_pdu_size = 0;
2108
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002109 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2110 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002111 break;
2112
2113 case L2CAP_MODE_ERTM:
2114 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002115 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002116 rfc.retrans_timeout = 0;
2117 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002118
2119 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2120 L2CAP_EXT_HDR_SIZE -
2121 L2CAP_SDULEN_SIZE -
2122 L2CAP_FCS_SIZE);
2123 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002124
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002125 l2cap_txwin_setup(chan);
2126
2127 rfc.txwin_size = min_t(u16, chan->tx_win,
2128 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002129
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002130 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2131 (unsigned long) &rfc);
2132
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002133 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2134 l2cap_add_opt_efs(&ptr, chan);
2135
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002136 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002137 break;
2138
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002139 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002140 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002141 chan->fcs = L2CAP_FCS_NONE;
2142 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002143 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002144
2145 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2146 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2147 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002148 break;
2149
2150 case L2CAP_MODE_STREAMING:
2151 rfc.mode = L2CAP_MODE_STREAMING;
2152 rfc.txwin_size = 0;
2153 rfc.max_transmit = 0;
2154 rfc.retrans_timeout = 0;
2155 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002156
2157 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2158 L2CAP_EXT_HDR_SIZE -
2159 L2CAP_SDULEN_SIZE -
2160 L2CAP_FCS_SIZE);
2161 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002162
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002163 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2164 (unsigned long) &rfc);
2165
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002166 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2167 l2cap_add_opt_efs(&ptr, chan);
2168
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002169 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002170 break;
2171
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002172 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002173 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002174 chan->fcs = L2CAP_FCS_NONE;
2175 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002176 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002177 break;
2178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002180 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002181 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
2183 return ptr - data;
2184}
2185
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002186static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002188 struct l2cap_conf_rsp *rsp = data;
2189 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002190 void *req = chan->conf_req;
2191 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002192 int type, hint, olen;
2193 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002194 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002195 struct l2cap_conf_efs efs;
2196 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002197 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002198 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002199 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002201 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002202
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002203 while (len >= L2CAP_CONF_OPT_SIZE) {
2204 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002206 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002207 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002208
2209 switch (type) {
2210 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002211 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002212 break;
2213
2214 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002215 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002216 break;
2217
2218 case L2CAP_CONF_QOS:
2219 break;
2220
Marcel Holtmann6464f352007-10-20 13:39:51 +02002221 case L2CAP_CONF_RFC:
2222 if (olen == sizeof(rfc))
2223 memcpy(&rfc, (void *) val, olen);
2224 break;
2225
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002226 case L2CAP_CONF_FCS:
2227 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002228 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002229 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002230
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002231 case L2CAP_CONF_EFS:
2232 remote_efs = 1;
2233 if (olen == sizeof(efs))
2234 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002235 break;
2236
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002237 case L2CAP_CONF_EWS:
2238 if (!enable_hs)
2239 return -ECONNREFUSED;
2240
2241 set_bit(FLAG_EXT_CTRL, &chan->flags);
2242 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002243 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002244 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002245 break;
2246
2247 default:
2248 if (hint)
2249 break;
2250
2251 result = L2CAP_CONF_UNKNOWN;
2252 *((u8 *) ptr++) = type;
2253 break;
2254 }
2255 }
2256
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002257 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002258 goto done;
2259
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002260 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002261 case L2CAP_MODE_STREAMING:
2262 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002263 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002264 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002265 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002266 break;
2267 }
2268
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002269 if (remote_efs) {
2270 if (__l2cap_efs_supported(chan))
2271 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2272 else
2273 return -ECONNREFUSED;
2274 }
2275
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002276 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002277 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002278
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002279 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002280 }
2281
2282done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002283 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002284 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002285 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002286
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002287 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002288 return -ECONNREFUSED;
2289
2290 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2291 sizeof(rfc), (unsigned long) &rfc);
2292 }
2293
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002294 if (result == L2CAP_CONF_SUCCESS) {
2295 /* Configure output options and let the other side know
2296 * which ones we don't like. */
2297
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002298 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2299 result = L2CAP_CONF_UNACCEPT;
2300 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002301 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002302 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002303 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002304 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002305
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002306 if (remote_efs) {
2307 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2308 efs.stype != L2CAP_SERV_NOTRAFIC &&
2309 efs.stype != chan->local_stype) {
2310
2311 result = L2CAP_CONF_UNACCEPT;
2312
2313 if (chan->num_conf_req >= 1)
2314 return -ECONNREFUSED;
2315
2316 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002317 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002318 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002319 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002320 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002321 result = L2CAP_CONF_PENDING;
2322 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002323 }
2324 }
2325
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002326 switch (rfc.mode) {
2327 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002328 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002329 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002330 break;
2331
2332 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002333 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2334 chan->remote_tx_win = rfc.txwin_size;
2335 else
2336 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2337
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002338 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002339
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002340 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2341 chan->conn->mtu -
2342 L2CAP_EXT_HDR_SIZE -
2343 L2CAP_SDULEN_SIZE -
2344 L2CAP_FCS_SIZE);
2345 rfc.max_pdu_size = cpu_to_le16(size);
2346 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002347
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002348 rfc.retrans_timeout =
2349 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2350 rfc.monitor_timeout =
2351 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002352
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002353 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002354
2355 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2356 sizeof(rfc), (unsigned long) &rfc);
2357
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002358 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2359 chan->remote_id = efs.id;
2360 chan->remote_stype = efs.stype;
2361 chan->remote_msdu = le16_to_cpu(efs.msdu);
2362 chan->remote_flush_to =
2363 le32_to_cpu(efs.flush_to);
2364 chan->remote_acc_lat =
2365 le32_to_cpu(efs.acc_lat);
2366 chan->remote_sdu_itime =
2367 le32_to_cpu(efs.sdu_itime);
2368 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2369 sizeof(efs), (unsigned long) &efs);
2370 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002371 break;
2372
2373 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002374 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2375 chan->conn->mtu -
2376 L2CAP_EXT_HDR_SIZE -
2377 L2CAP_SDULEN_SIZE -
2378 L2CAP_FCS_SIZE);
2379 rfc.max_pdu_size = cpu_to_le16(size);
2380 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002381
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002382 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002383
2384 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2385 sizeof(rfc), (unsigned long) &rfc);
2386
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002387 break;
2388
2389 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002390 result = L2CAP_CONF_UNACCEPT;
2391
2392 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002393 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002394 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002395
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002396 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002397 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002398 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002399 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002400 rsp->result = cpu_to_le16(result);
2401 rsp->flags = cpu_to_le16(0x0000);
2402
2403 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404}
2405
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002406static 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 -03002407{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002408 struct l2cap_conf_req *req = data;
2409 void *ptr = req->data;
2410 int type, olen;
2411 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002412 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002413 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002414
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002415 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002416
2417 while (len >= L2CAP_CONF_OPT_SIZE) {
2418 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2419
2420 switch (type) {
2421 case L2CAP_CONF_MTU:
2422 if (val < L2CAP_DEFAULT_MIN_MTU) {
2423 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002424 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002425 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002426 chan->imtu = val;
2427 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002428 break;
2429
2430 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002431 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002432 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002433 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002434 break;
2435
2436 case L2CAP_CONF_RFC:
2437 if (olen == sizeof(rfc))
2438 memcpy(&rfc, (void *)val, olen);
2439
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002440 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002441 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002442 return -ECONNREFUSED;
2443
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002444 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002445
2446 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2447 sizeof(rfc), (unsigned long) &rfc);
2448 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002449
2450 case L2CAP_CONF_EWS:
2451 chan->tx_win = min_t(u16, val,
2452 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002453 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2454 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002455 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002456
2457 case L2CAP_CONF_EFS:
2458 if (olen == sizeof(efs))
2459 memcpy(&efs, (void *)val, olen);
2460
2461 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2462 efs.stype != L2CAP_SERV_NOTRAFIC &&
2463 efs.stype != chan->local_stype)
2464 return -ECONNREFUSED;
2465
2466 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2467 sizeof(efs), (unsigned long) &efs);
2468 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002469 }
2470 }
2471
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002472 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002473 return -ECONNREFUSED;
2474
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002475 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002476
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002477 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002478 switch (rfc.mode) {
2479 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002480 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2481 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2482 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002483
2484 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2485 chan->local_msdu = le16_to_cpu(efs.msdu);
2486 chan->local_sdu_itime =
2487 le32_to_cpu(efs.sdu_itime);
2488 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2489 chan->local_flush_to =
2490 le32_to_cpu(efs.flush_to);
2491 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002492 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002493
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002494 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002495 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002496 }
2497 }
2498
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002499 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002500 req->flags = cpu_to_le16(0x0000);
2501
2502 return ptr - data;
2503}
2504
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002505static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506{
2507 struct l2cap_conf_rsp *rsp = data;
2508 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002510 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002512 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002513 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002514 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 return ptr - data;
2517}
2518
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002519void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002520{
2521 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002522 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002523 u8 buf[128];
2524
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002525 rsp.scid = cpu_to_le16(chan->dcid);
2526 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002527 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2528 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2529 l2cap_send_cmd(conn, chan->ident,
2530 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2531
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002532 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002533 return;
2534
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002535 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2536 l2cap_build_conf_req(chan, buf), buf);
2537 chan->num_conf_req++;
2538}
2539
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002540static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002541{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002542 int type, olen;
2543 unsigned long val;
2544 struct l2cap_conf_rfc rfc;
2545
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002546 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002547
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002548 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002549 return;
2550
2551 while (len >= L2CAP_CONF_OPT_SIZE) {
2552 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2553
2554 switch (type) {
2555 case L2CAP_CONF_RFC:
2556 if (olen == sizeof(rfc))
2557 memcpy(&rfc, (void *)val, olen);
2558 goto done;
2559 }
2560 }
2561
Mat Martineau36e999a2011-12-08 17:23:21 -08002562 /* Use sane default values in case a misbehaving remote device
2563 * did not send an RFC option.
2564 */
2565 rfc.mode = chan->mode;
2566 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2567 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2568 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2569
2570 BT_ERR("Expected RFC option was not found, using defaults");
2571
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002572done:
2573 switch (rfc.mode) {
2574 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002575 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2576 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2577 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002578 break;
2579 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002580 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002581 }
2582}
2583
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002584static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2585{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002586 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002587
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002588 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002589 return 0;
2590
2591 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2592 cmd->ident == conn->info_ident) {
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02002593 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002594
2595 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002596 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002597
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002598 l2cap_conn_start(conn);
2599 }
2600
2601 return 0;
2602}
2603
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2605{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2607 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002608 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002609 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002610 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
2612 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002613 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2616
2617 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002618 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2619 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 result = L2CAP_CR_BAD_PSM;
2621 goto sendresp;
2622 }
2623
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002624 parent = pchan->sk;
2625
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002626 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002627 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002628
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002629 /* Check if the ACL is secure enough (if not SDP) */
2630 if (psm != cpu_to_le16(0x0001) &&
2631 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002632 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002633 result = L2CAP_CR_SEC_BLOCK;
2634 goto response;
2635 }
2636
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 result = L2CAP_CR_NO_MEM;
2638
2639 /* Check for backlog size */
2640 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002641 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 goto response;
2643 }
2644
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002645 chan = pchan->ops->new_connection(pchan->data);
2646 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 goto response;
2648
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002649 sk = chan->sk;
2650
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002652 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002654 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 goto response;
2656 }
2657
2658 hci_conn_hold(conn->hcon);
2659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 bacpy(&bt_sk(sk)->src, conn->src);
2661 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002662 chan->psm = psm;
2663 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002665 bt_accept_enqueue(parent, sk);
2666
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02002667 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002668
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002669 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002671 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002673 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674
Marcel Holtmann984947d2009-02-06 23:35:19 +01002675 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002676 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002677 if (bt_sk(sk)->defer_setup) {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002678 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002679 result = L2CAP_CR_PEND;
2680 status = L2CAP_CS_AUTHOR_PEND;
2681 parent->sk_data_ready(parent, 0);
2682 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002683 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002684 result = L2CAP_CR_SUCCESS;
2685 status = L2CAP_CS_NO_INFO;
2686 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002687 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002688 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002689 result = L2CAP_CR_PEND;
2690 status = L2CAP_CS_AUTHEN_PEND;
2691 }
2692 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002693 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002694 result = L2CAP_CR_PEND;
2695 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 }
2697
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002699 release_sock(parent);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002700 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
2702sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002703 rsp.scid = cpu_to_le16(scid);
2704 rsp.dcid = cpu_to_le16(dcid);
2705 rsp.result = cpu_to_le16(result);
2706 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002708
2709 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2710 struct l2cap_info_req info;
2711 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2712
2713 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2714 conn->info_ident = l2cap_get_ident(conn);
2715
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02002716 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002717 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2718
2719 l2cap_send_cmd(conn, conn->info_ident,
2720 L2CAP_INFO_REQ, sizeof(info), &info);
2721 }
2722
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002723 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002724 result == L2CAP_CR_SUCCESS) {
2725 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002726 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002727 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002728 l2cap_build_conf_req(chan, buf), buf);
2729 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002730 }
2731
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 return 0;
2733}
2734
2735static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2736{
2737 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2738 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002739 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 struct sock *sk;
2741 u8 req[128];
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002742 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743
2744 scid = __le16_to_cpu(rsp->scid);
2745 dcid = __le16_to_cpu(rsp->dcid);
2746 result = __le16_to_cpu(rsp->result);
2747 status = __le16_to_cpu(rsp->status);
2748
Andrei Emeltchenko1b009c92012-02-21 12:54:54 +02002749 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
2750 dcid, scid, result, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002752 mutex_lock(&conn->chan_lock);
2753
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 if (scid) {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002755 chan = __l2cap_get_chan_by_scid(conn, scid);
2756 if (!chan) {
2757 err = -EFAULT;
2758 goto unlock;
2759 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 } else {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002761 chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
2762 if (!chan) {
2763 err = -EFAULT;
2764 goto unlock;
2765 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 }
2767
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002768 err = 0;
2769
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002770 sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002771 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002772
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 switch (result) {
2774 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002775 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002776 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002777 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002778 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002779
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002780 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002781 break;
2782
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002784 l2cap_build_conf_req(chan, req), req);
2785 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 break;
2787
2788 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002789 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 break;
2791
2792 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002793 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 break;
2795 }
2796
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002797 release_sock(sk);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002798
2799unlock:
2800 mutex_unlock(&conn->chan_lock);
2801
2802 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803}
2804
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002805static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002806{
2807 /* FCS is enabled only in ERTM or streaming mode, if one or both
2808 * sides request it.
2809 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002810 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002811 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002812 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002813 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002814}
2815
Al Viro88219a02007-07-29 00:17:25 -07002816static 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 -07002817{
2818 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2819 u16 dcid, flags;
2820 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002821 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002823 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824
2825 dcid = __le16_to_cpu(req->dcid);
2826 flags = __le16_to_cpu(req->flags);
2827
2828 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2829
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002830 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002831 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 return -ENOENT;
2833
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002834 sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002835 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002836
David S. Miller033b1142011-07-21 13:38:42 -07002837 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002838 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002839
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002840 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2841 rej.scid = cpu_to_le16(chan->scid);
2842 rej.dcid = cpu_to_le16(chan->dcid);
2843
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002844 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2845 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002846 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002847 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002848
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002849 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002850 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002851 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002852 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002853 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002854 L2CAP_CONF_REJECT, flags), rsp);
2855 goto unlock;
2856 }
2857
2858 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002859 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2860 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
2862 if (flags & 0x0001) {
2863 /* Incomplete config. Send empty response. */
2864 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002865 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002866 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 goto unlock;
2868 }
2869
2870 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002871 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002872 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002873 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002877 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002878 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002879
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002880 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002881 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002882
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002883 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002884 goto unlock;
2885
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002886 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002887 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002888
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002889 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002890
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002891 chan->next_tx_seq = 0;
2892 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002893 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002894 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002895 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002896
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02002897 l2cap_chan_ready(chan);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002898 goto unlock;
2899 }
2900
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002901 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002902 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002904 l2cap_build_conf_req(chan, buf), buf);
2905 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 }
2907
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002908 /* Got Conf Rsp PENDING from remote side and asume we sent
2909 Conf Rsp PENDING in the code above */
2910 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2911 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2912
2913 /* check compatibility */
2914
2915 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2916 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2917
2918 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002919 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002920 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2921 }
2922
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923unlock:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002924 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 return 0;
2926}
2927
2928static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2929{
2930 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2931 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002932 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002934 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935
2936 scid = __le16_to_cpu(rsp->scid);
2937 flags = __le16_to_cpu(rsp->flags);
2938 result = __le16_to_cpu(rsp->result);
2939
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002940 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2941 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002943 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002944 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 return 0;
2946
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002947 sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002948 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002949
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 switch (result) {
2951 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002952 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002953 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 break;
2955
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002956 case L2CAP_CONF_PENDING:
2957 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2958
2959 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2960 char buf[64];
2961
2962 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2963 buf, &result);
2964 if (len < 0) {
2965 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2966 goto done;
2967 }
2968
2969 /* check compatibility */
2970
2971 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2972 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2973
2974 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002975 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002976 L2CAP_CONF_SUCCESS, 0x0000), buf);
2977 }
2978 goto done;
2979
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002981 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002982 char req[64];
2983
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002984 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002985 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002986 goto done;
2987 }
2988
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002989 /* throw out any old stored conf requests */
2990 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002991 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2992 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002993 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002994 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002995 goto done;
2996 }
2997
2998 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2999 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003000 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003001 if (result != L2CAP_CONF_SUCCESS)
3002 goto done;
3003 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 }
3005
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09003006 default:
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +02003007 __l2cap_chan_set_err(chan, ECONNRESET);
3008
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01003009 __set_chan_timer(chan,
3010 msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT));
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003011 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 goto done;
3013 }
3014
3015 if (flags & 0x01)
3016 goto done;
3017
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003018 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003019
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003020 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003021 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003022
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003023 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003024 chan->next_tx_seq = 0;
3025 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003026 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003027 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003028 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003029
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02003030 l2cap_chan_ready(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 }
3032
3033done:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003034 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 return 0;
3036}
3037
3038static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3039{
3040 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3041 struct l2cap_disconn_rsp rsp;
3042 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003043 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 struct sock *sk;
3045
3046 scid = __le16_to_cpu(req->scid);
3047 dcid = __le16_to_cpu(req->dcid);
3048
3049 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3050
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003051 mutex_lock(&conn->chan_lock);
3052
3053 chan = __l2cap_get_chan_by_scid(conn, dcid);
3054 if (!chan) {
3055 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003057 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003059 sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003060 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003061
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003062 rsp.dcid = cpu_to_le16(chan->scid);
3063 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3065
3066 sk->sk_shutdown = SHUTDOWN_MASK;
3067
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003068 l2cap_chan_del(chan, ECONNRESET);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003069 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003071 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003072
3073 mutex_unlock(&conn->chan_lock);
3074
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 return 0;
3076}
3077
3078static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3079{
3080 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3081 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003082 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083 struct sock *sk;
3084
3085 scid = __le16_to_cpu(rsp->scid);
3086 dcid = __le16_to_cpu(rsp->dcid);
3087
3088 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3089
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003090 mutex_lock(&conn->chan_lock);
3091
3092 chan = __l2cap_get_chan_by_scid(conn, scid);
3093 if (!chan) {
3094 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003098 sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003099 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003100
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003101 l2cap_chan_del(chan, 0);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003102 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003104 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003105
3106 mutex_unlock(&conn->chan_lock);
3107
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 return 0;
3109}
3110
3111static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3112{
3113 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 u16 type;
3115
3116 type = __le16_to_cpu(req->type);
3117
3118 BT_DBG("type 0x%4.4x", type);
3119
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003120 if (type == L2CAP_IT_FEAT_MASK) {
3121 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003122 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003123 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3124 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3125 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003126 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003127 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3128 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003129 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003130 feat_mask |= L2CAP_FEAT_EXT_FLOW
3131 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003132
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003133 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003134 l2cap_send_cmd(conn, cmd->ident,
3135 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003136 } else if (type == L2CAP_IT_FIXED_CHAN) {
3137 u8 buf[12];
3138 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003139
3140 if (enable_hs)
3141 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3142 else
3143 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3144
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003145 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3146 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003147 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003148 l2cap_send_cmd(conn, cmd->ident,
3149 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003150 } else {
3151 struct l2cap_info_rsp rsp;
3152 rsp.type = cpu_to_le16(type);
3153 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3154 l2cap_send_cmd(conn, cmd->ident,
3155 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003157
3158 return 0;
3159}
3160
3161static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3162{
3163 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3164 u16 type, result;
3165
3166 type = __le16_to_cpu(rsp->type);
3167 result = __le16_to_cpu(rsp->result);
3168
3169 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3170
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003171 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3172 if (cmd->ident != conn->info_ident ||
3173 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3174 return 0;
3175
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02003176 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003177
Ville Tervoadb08ed2010-08-04 09:43:33 +03003178 if (result != L2CAP_IR_SUCCESS) {
3179 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3180 conn->info_ident = 0;
3181
3182 l2cap_conn_start(conn);
3183
3184 return 0;
3185 }
3186
Marcel Holtmann984947d2009-02-06 23:35:19 +01003187 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003188 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003189
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003190 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003191 struct l2cap_info_req req;
3192 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3193
3194 conn->info_ident = l2cap_get_ident(conn);
3195
3196 l2cap_send_cmd(conn, conn->info_ident,
3197 L2CAP_INFO_REQ, sizeof(req), &req);
3198 } else {
3199 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3200 conn->info_ident = 0;
3201
3202 l2cap_conn_start(conn);
3203 }
3204 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003205 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003206 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003207
3208 l2cap_conn_start(conn);
3209 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003210
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 return 0;
3212}
3213
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003214static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3215 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3216 void *data)
3217{
3218 struct l2cap_create_chan_req *req = data;
3219 struct l2cap_create_chan_rsp rsp;
3220 u16 psm, scid;
3221
3222 if (cmd_len != sizeof(*req))
3223 return -EPROTO;
3224
3225 if (!enable_hs)
3226 return -EINVAL;
3227
3228 psm = le16_to_cpu(req->psm);
3229 scid = le16_to_cpu(req->scid);
3230
3231 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3232
3233 /* Placeholder: Always reject */
3234 rsp.dcid = 0;
3235 rsp.scid = cpu_to_le16(scid);
3236 rsp.result = L2CAP_CR_NO_MEM;
3237 rsp.status = L2CAP_CS_NO_INFO;
3238
3239 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3240 sizeof(rsp), &rsp);
3241
3242 return 0;
3243}
3244
3245static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3246 struct l2cap_cmd_hdr *cmd, void *data)
3247{
3248 BT_DBG("conn %p", conn);
3249
3250 return l2cap_connect_rsp(conn, cmd, data);
3251}
3252
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003253static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3254 u16 icid, u16 result)
3255{
3256 struct l2cap_move_chan_rsp rsp;
3257
3258 BT_DBG("icid %d, result %d", icid, result);
3259
3260 rsp.icid = cpu_to_le16(icid);
3261 rsp.result = cpu_to_le16(result);
3262
3263 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3264}
3265
3266static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3267 struct l2cap_chan *chan, u16 icid, u16 result)
3268{
3269 struct l2cap_move_chan_cfm cfm;
3270 u8 ident;
3271
3272 BT_DBG("icid %d, result %d", icid, result);
3273
3274 ident = l2cap_get_ident(conn);
3275 if (chan)
3276 chan->ident = ident;
3277
3278 cfm.icid = cpu_to_le16(icid);
3279 cfm.result = cpu_to_le16(result);
3280
3281 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3282}
3283
3284static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3285 u16 icid)
3286{
3287 struct l2cap_move_chan_cfm_rsp rsp;
3288
3289 BT_DBG("icid %d", icid);
3290
3291 rsp.icid = cpu_to_le16(icid);
3292 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3293}
3294
3295static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3296 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3297{
3298 struct l2cap_move_chan_req *req = data;
3299 u16 icid = 0;
3300 u16 result = L2CAP_MR_NOT_ALLOWED;
3301
3302 if (cmd_len != sizeof(*req))
3303 return -EPROTO;
3304
3305 icid = le16_to_cpu(req->icid);
3306
3307 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3308
3309 if (!enable_hs)
3310 return -EINVAL;
3311
3312 /* Placeholder: Always refuse */
3313 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3314
3315 return 0;
3316}
3317
3318static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3319 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3320{
3321 struct l2cap_move_chan_rsp *rsp = data;
3322 u16 icid, result;
3323
3324 if (cmd_len != sizeof(*rsp))
3325 return -EPROTO;
3326
3327 icid = le16_to_cpu(rsp->icid);
3328 result = le16_to_cpu(rsp->result);
3329
3330 BT_DBG("icid %d, result %d", icid, result);
3331
3332 /* Placeholder: Always unconfirmed */
3333 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3334
3335 return 0;
3336}
3337
3338static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3339 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3340{
3341 struct l2cap_move_chan_cfm *cfm = data;
3342 u16 icid, result;
3343
3344 if (cmd_len != sizeof(*cfm))
3345 return -EPROTO;
3346
3347 icid = le16_to_cpu(cfm->icid);
3348 result = le16_to_cpu(cfm->result);
3349
3350 BT_DBG("icid %d, result %d", icid, result);
3351
3352 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3353
3354 return 0;
3355}
3356
3357static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3358 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3359{
3360 struct l2cap_move_chan_cfm_rsp *rsp = data;
3361 u16 icid;
3362
3363 if (cmd_len != sizeof(*rsp))
3364 return -EPROTO;
3365
3366 icid = le16_to_cpu(rsp->icid);
3367
3368 BT_DBG("icid %d", icid);
3369
3370 return 0;
3371}
3372
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003373static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003374 u16 to_multiplier)
3375{
3376 u16 max_latency;
3377
3378 if (min > max || min < 6 || max > 3200)
3379 return -EINVAL;
3380
3381 if (to_multiplier < 10 || to_multiplier > 3200)
3382 return -EINVAL;
3383
3384 if (max >= to_multiplier * 8)
3385 return -EINVAL;
3386
3387 max_latency = (to_multiplier * 8 / max) - 1;
3388 if (latency > 499 || latency > max_latency)
3389 return -EINVAL;
3390
3391 return 0;
3392}
3393
3394static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3395 struct l2cap_cmd_hdr *cmd, u8 *data)
3396{
3397 struct hci_conn *hcon = conn->hcon;
3398 struct l2cap_conn_param_update_req *req;
3399 struct l2cap_conn_param_update_rsp rsp;
3400 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003401 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003402
3403 if (!(hcon->link_mode & HCI_LM_MASTER))
3404 return -EINVAL;
3405
3406 cmd_len = __le16_to_cpu(cmd->len);
3407 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3408 return -EPROTO;
3409
3410 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003411 min = __le16_to_cpu(req->min);
3412 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003413 latency = __le16_to_cpu(req->latency);
3414 to_multiplier = __le16_to_cpu(req->to_multiplier);
3415
3416 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3417 min, max, latency, to_multiplier);
3418
3419 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003420
3421 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3422 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003423 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3424 else
3425 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3426
3427 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3428 sizeof(rsp), &rsp);
3429
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003430 if (!err)
3431 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3432
Claudio Takahaside731152011-02-11 19:28:55 -02003433 return 0;
3434}
3435
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003436static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3437 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3438{
3439 int err = 0;
3440
3441 switch (cmd->code) {
3442 case L2CAP_COMMAND_REJ:
3443 l2cap_command_rej(conn, cmd, data);
3444 break;
3445
3446 case L2CAP_CONN_REQ:
3447 err = l2cap_connect_req(conn, cmd, data);
3448 break;
3449
3450 case L2CAP_CONN_RSP:
3451 err = l2cap_connect_rsp(conn, cmd, data);
3452 break;
3453
3454 case L2CAP_CONF_REQ:
3455 err = l2cap_config_req(conn, cmd, cmd_len, data);
3456 break;
3457
3458 case L2CAP_CONF_RSP:
3459 err = l2cap_config_rsp(conn, cmd, data);
3460 break;
3461
3462 case L2CAP_DISCONN_REQ:
3463 err = l2cap_disconnect_req(conn, cmd, data);
3464 break;
3465
3466 case L2CAP_DISCONN_RSP:
3467 err = l2cap_disconnect_rsp(conn, cmd, data);
3468 break;
3469
3470 case L2CAP_ECHO_REQ:
3471 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3472 break;
3473
3474 case L2CAP_ECHO_RSP:
3475 break;
3476
3477 case L2CAP_INFO_REQ:
3478 err = l2cap_information_req(conn, cmd, data);
3479 break;
3480
3481 case L2CAP_INFO_RSP:
3482 err = l2cap_information_rsp(conn, cmd, data);
3483 break;
3484
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003485 case L2CAP_CREATE_CHAN_REQ:
3486 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3487 break;
3488
3489 case L2CAP_CREATE_CHAN_RSP:
3490 err = l2cap_create_channel_rsp(conn, cmd, data);
3491 break;
3492
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003493 case L2CAP_MOVE_CHAN_REQ:
3494 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3495 break;
3496
3497 case L2CAP_MOVE_CHAN_RSP:
3498 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3499 break;
3500
3501 case L2CAP_MOVE_CHAN_CFM:
3502 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3503 break;
3504
3505 case L2CAP_MOVE_CHAN_CFM_RSP:
3506 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3507 break;
3508
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003509 default:
3510 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3511 err = -EINVAL;
3512 break;
3513 }
3514
3515 return err;
3516}
3517
3518static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3519 struct l2cap_cmd_hdr *cmd, u8 *data)
3520{
3521 switch (cmd->code) {
3522 case L2CAP_COMMAND_REJ:
3523 return 0;
3524
3525 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003526 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003527
3528 case L2CAP_CONN_PARAM_UPDATE_RSP:
3529 return 0;
3530
3531 default:
3532 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3533 return -EINVAL;
3534 }
3535}
3536
3537static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3538 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539{
3540 u8 *data = skb->data;
3541 int len = skb->len;
3542 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003543 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544
3545 l2cap_raw_recv(conn, skb);
3546
3547 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003548 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3550 data += L2CAP_CMD_HDR_SIZE;
3551 len -= L2CAP_CMD_HDR_SIZE;
3552
Al Viro88219a02007-07-29 00:17:25 -07003553 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554
Al Viro88219a02007-07-29 00:17:25 -07003555 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 -07003556
Al Viro88219a02007-07-29 00:17:25 -07003557 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 BT_DBG("corrupted command");
3559 break;
3560 }
3561
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003562 if (conn->hcon->type == LE_LINK)
3563 err = l2cap_le_sig_cmd(conn, &cmd, data);
3564 else
3565 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566
3567 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003568 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003569
3570 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571
3572 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003573 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3575 }
3576
Al Viro88219a02007-07-29 00:17:25 -07003577 data += cmd_len;
3578 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 }
3580
3581 kfree_skb(skb);
3582}
3583
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003584static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003585{
3586 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003587 int hdr_size;
3588
3589 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3590 hdr_size = L2CAP_EXT_HDR_SIZE;
3591 else
3592 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003593
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003594 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003595 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003596 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3597 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3598
3599 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003600 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003601 }
3602 return 0;
3603}
3604
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003605static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003606{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003607 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003608
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003609 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003610
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003611 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003612
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003613 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003614 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003615 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003616 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003617 }
3618
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003619 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003620 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003621
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003622 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003623
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003624 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003625 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003626 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003627 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003628 }
3629}
3630
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003631static 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 -03003632{
3633 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003634 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003635
3636 bt_cb(skb)->tx_seq = tx_seq;
3637 bt_cb(skb)->sar = sar;
3638
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003639 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003640
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003641 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003642
Szymon Janc039d9572011-11-16 09:32:19 +01003643 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003644 if (bt_cb(next_skb)->tx_seq == tx_seq)
3645 return -EINVAL;
3646
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003647 next_tx_seq_offset = __seq_offset(chan,
3648 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003649
3650 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003651 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003652 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003653 }
3654
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003655 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003656 next_skb = NULL;
3657 else
3658 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3659 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003660
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003661 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003662
3663 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003664}
3665
Mat Martineau84084a32011-07-22 14:54:00 -07003666static void append_skb_frag(struct sk_buff *skb,
3667 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003668{
Mat Martineau84084a32011-07-22 14:54:00 -07003669 /* skb->len reflects data in skb as well as all fragments
3670 * skb->data_len reflects only data in fragments
3671 */
3672 if (!skb_has_frag_list(skb))
3673 skb_shinfo(skb)->frag_list = new_frag;
3674
3675 new_frag->next = NULL;
3676
3677 (*last_frag)->next = new_frag;
3678 *last_frag = new_frag;
3679
3680 skb->len += new_frag->len;
3681 skb->data_len += new_frag->len;
3682 skb->truesize += new_frag->truesize;
3683}
3684
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003685static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003686{
3687 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003688
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003689 switch (__get_ctrl_sar(chan, control)) {
3690 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003691 if (chan->sdu)
3692 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003693
Mat Martineau84084a32011-07-22 14:54:00 -07003694 err = chan->ops->recv(chan->data, skb);
3695 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003696
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003697 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003698 if (chan->sdu)
3699 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003700
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003701 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003702 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003703
Mat Martineau84084a32011-07-22 14:54:00 -07003704 if (chan->sdu_len > chan->imtu) {
3705 err = -EMSGSIZE;
3706 break;
3707 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003708
Mat Martineau84084a32011-07-22 14:54:00 -07003709 if (skb->len >= chan->sdu_len)
3710 break;
3711
3712 chan->sdu = skb;
3713 chan->sdu_last_frag = skb;
3714
3715 skb = NULL;
3716 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003717 break;
3718
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003719 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003720 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003721 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003722
Mat Martineau84084a32011-07-22 14:54:00 -07003723 append_skb_frag(chan->sdu, skb,
3724 &chan->sdu_last_frag);
3725 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003726
Mat Martineau84084a32011-07-22 14:54:00 -07003727 if (chan->sdu->len >= chan->sdu_len)
3728 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003729
Mat Martineau84084a32011-07-22 14:54:00 -07003730 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003731 break;
3732
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003733 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003734 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003735 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003736
Mat Martineau84084a32011-07-22 14:54:00 -07003737 append_skb_frag(chan->sdu, skb,
3738 &chan->sdu_last_frag);
3739 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003740
Mat Martineau84084a32011-07-22 14:54:00 -07003741 if (chan->sdu->len != chan->sdu_len)
3742 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003743
Mat Martineau84084a32011-07-22 14:54:00 -07003744 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003745
Mat Martineau84084a32011-07-22 14:54:00 -07003746 if (!err) {
3747 /* Reassembly complete */
3748 chan->sdu = NULL;
3749 chan->sdu_last_frag = NULL;
3750 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003751 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003752 break;
3753 }
3754
Mat Martineau84084a32011-07-22 14:54:00 -07003755 if (err) {
3756 kfree_skb(skb);
3757 kfree_skb(chan->sdu);
3758 chan->sdu = NULL;
3759 chan->sdu_last_frag = NULL;
3760 chan->sdu_len = 0;
3761 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003762
Mat Martineau84084a32011-07-22 14:54:00 -07003763 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003764}
3765
Mat Martineau26f880d2011-07-07 09:39:01 -07003766static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003767{
Mat Martineau26f880d2011-07-07 09:39:01 -07003768 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003769
Mat Martineau26f880d2011-07-07 09:39:01 -07003770 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3771
Szymon Janc77f918b2012-01-11 10:59:48 +01003772 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003773}
3774
3775static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3776{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003777 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003778
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003779 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003780 goto done;
3781
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003782 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003783 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003784 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003785 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003786 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003787
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003788 __clear_retrans_timer(chan);
3789 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003790
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003791 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003792
3793done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003794 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3795 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003796
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003797 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003798}
3799
Mat Martineaue3281402011-07-07 09:39:02 -07003800void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003801{
Mat Martineaue3281402011-07-07 09:39:02 -07003802 if (chan->mode == L2CAP_MODE_ERTM) {
3803 if (busy)
3804 l2cap_ertm_enter_local_busy(chan);
3805 else
3806 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003807 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003808}
3809
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003810static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003811{
3812 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003813 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003814
Mat Martineaue3281402011-07-07 09:39:02 -07003815 while ((skb = skb_peek(&chan->srej_q)) &&
3816 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3817 int err;
3818
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003819 if (bt_cb(skb)->tx_seq != tx_seq)
3820 break;
3821
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003822 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003823 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003824 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003825
3826 if (err < 0) {
3827 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3828 break;
3829 }
3830
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003831 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3832 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003833 }
3834}
3835
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003836static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003837{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003838 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003839 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003840
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003841 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003842 if (l->tx_seq == tx_seq) {
3843 list_del(&l->list);
3844 kfree(l);
3845 return;
3846 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003847 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003848 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003849 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003850 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003851 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003852 }
3853}
3854
Szymon Jancaef89f22011-11-16 09:32:18 +01003855static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003856{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003857 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003858 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003859
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003860 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003861 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003862 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003863 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003864
3865 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003866 if (!new)
3867 return -ENOMEM;
3868
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003869 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003870
3871 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3872
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003873 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003874 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003875
3876 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003877
3878 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003879}
3880
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003881static 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 -03003882{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003883 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003884 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003885 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003886 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003887 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003888 int err = 0;
3889
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003890 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 -03003891 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003892
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003893 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003894 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003895 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003896 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003897 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003898 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003899 }
3900
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003901 chan->expected_ack_seq = req_seq;
3902 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003903
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003904 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003905
3906 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003907 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003908 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003909 goto drop;
3910 }
3911
Szymon Janc77f918b2012-01-11 10:59:48 +01003912 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3913 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3914 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003915 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003916 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003917
Mat Martineau02f1b642011-06-29 14:35:19 -07003918 if (tx_seq == chan->expected_tx_seq)
3919 goto expected;
3920
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003921 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003922 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003923
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003924 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003925 struct srej_list, list);
3926 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003927 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003928 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003929
3930 list_del(&first->list);
3931 kfree(first);
3932
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003933 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003934 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003935 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003936 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003937 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003938 }
3939 } else {
3940 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003941
3942 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003943 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003944 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003945
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003946 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003947 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003948 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003949 return 0;
3950 }
3951 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003952
3953 err = l2cap_send_srejframe(chan, tx_seq);
3954 if (err < 0) {
3955 l2cap_send_disconn_req(chan->conn, chan, -err);
3956 return err;
3957 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003958 }
3959 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003960 expected_tx_seq_offset = __seq_offset(chan,
3961 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003962
3963 /* duplicated tx_seq */
3964 if (tx_seq_offset < expected_tx_seq_offset)
3965 goto drop;
3966
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003967 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003968
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003969 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003970
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003971 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003972 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003973
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003974 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003975 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003976
Szymon Janc0ef3ef02012-01-11 10:59:46 +01003977 /* Set P-bit only if there are some I-frames to ack. */
3978 if (__clear_ack_timer(chan))
3979 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003980
Szymon Jancaef89f22011-11-16 09:32:18 +01003981 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. Padovan1c2acff2009-08-20 22:25:57 -03003986 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003987 return 0;
3988
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003989expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003990 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003991
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003992 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003993 bt_cb(skb)->tx_seq = tx_seq;
3994 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003995 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003996 return 0;
3997 }
3998
Mat Martineau84084a32011-07-22 14:54:00 -07003999 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004000 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4001
Mat Martineaue3281402011-07-07 09:39:02 -07004002 if (err < 0) {
4003 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4004 return err;
4005 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03004006
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004007 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004008 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004009 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03004010 }
4011
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03004012
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004013 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
4014 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004015 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03004016 else
4017 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03004018
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004019 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03004020
4021drop:
4022 kfree_skb(skb);
4023 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004024}
4025
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004026static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004027{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004028 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004029 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004030
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004031 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004032 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004033
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004034 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004035 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4036 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4037 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004038 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004039 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004040
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004041 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004042 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004043 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004044 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004045 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004046
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004047 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004048 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004049
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004050 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004051 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004052
4053 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004054 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004055 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004056 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004057
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004058 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4059 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004060 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004061 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004062 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004063 }
4064}
4065
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004066static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004067{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004068 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004069
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004070 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004071
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004072 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004073
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004074 chan->expected_ack_seq = tx_seq;
4075 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004076
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004077 if (__is_ctrl_final(chan, rx_control)) {
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 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004081 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004082
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004083 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4084 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004085 }
4086}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004087static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004088{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004089 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004090
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004091 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004092
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004093 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004094
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004095 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004096 chan->expected_ack_seq = tx_seq;
4097 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004098
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004099 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004100 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004101
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004102 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004103
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004104 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004105 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004106 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004107 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004108 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004109 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004110 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004111 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004112 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004113 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004114 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004115 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004116 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004117 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004118 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004119 }
4120 }
4121}
4122
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004123static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004124{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004125 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004126
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004127 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004128
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004129 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004130 chan->expected_ack_seq = tx_seq;
4131 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004132
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004133 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004134 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004135
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004136 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004137 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004138 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004139 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004140 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004141 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004142
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004143 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004144 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004145 } else {
4146 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4147 l2cap_send_sframe(chan, rx_control);
4148 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004149}
4150
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004151static 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 -03004152{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004153 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004154
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004155 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004156 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004157 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004158 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004159 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004160 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004161 }
4162
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004163 switch (__get_ctrl_super(chan, rx_control)) {
4164 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004165 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004166 break;
4167
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004168 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004169 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004170 break;
4171
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004172 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004173 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004174 break;
4175
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004176 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004177 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004178 break;
4179 }
4180
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004181 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004182 return 0;
4183}
4184
Szymon Janccad8f1d2012-01-23 10:06:05 +01004185static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004186{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004187 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004188 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004189 int len, next_tx_seq_offset, req_seq_offset;
4190
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004191 control = __get_control(chan, skb->data);
4192 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004193 len = skb->len;
4194
4195 /*
4196 * We can just drop the corrupted I-frame here.
4197 * Receiver will miss it and start proper recovery
4198 * procedures and ask retransmission.
4199 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004200 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004201 goto drop;
4202
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004203 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004204 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004205
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004206 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004207 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004208
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004209 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004210 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004211 goto drop;
4212 }
4213
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004214 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004215
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004216 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4217
4218 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4219 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004220
4221 /* check for invalid req-seq */
4222 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004223 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004224 goto drop;
4225 }
4226
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004227 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004228 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004229 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004230 goto drop;
4231 }
4232
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004233 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004234 } else {
4235 if (len != 0) {
4236 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004237 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004238 goto drop;
4239 }
4240
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004241 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004242 }
4243
4244 return 0;
4245
4246drop:
4247 kfree_skb(skb);
4248 return 0;
4249}
4250
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4252{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004253 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07004254 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004255 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004256 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004257 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004259 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004260 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 BT_DBG("unknown cid 0x%4.4x", cid);
4262 goto drop;
4263 }
4264
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004265 sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004266 lock_sock(sk);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004267
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004268 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004270 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 goto drop;
4272
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004273 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004274 case L2CAP_MODE_BASIC:
4275 /* If socket recv buffers overflows we drop data here
4276 * which is *bad* because L2CAP has to be reliable.
4277 * But we don't have any other choice. L2CAP doesn't
4278 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004280 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004281 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004283 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004284 goto done;
4285 break;
4286
4287 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004288 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004289
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004290 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004291
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004292 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004293 control = __get_control(chan, skb->data);
4294 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004295 len = skb->len;
4296
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004297 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004298 goto drop;
4299
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004300 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004301 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004302
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004303 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004304 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004305
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004306 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004307 goto drop;
4308
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004309 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004310
Mat Martineau84084a32011-07-22 14:54:00 -07004311 if (chan->expected_tx_seq != tx_seq) {
4312 /* Frame(s) missing - must discard partial SDU */
4313 kfree_skb(chan->sdu);
4314 chan->sdu = NULL;
4315 chan->sdu_last_frag = NULL;
4316 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004317
Mat Martineau84084a32011-07-22 14:54:00 -07004318 /* TODO: Notify userland of missing data */
4319 }
4320
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004321 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004322
4323 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4324 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004325
4326 goto done;
4327
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004328 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004329 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004330 break;
4331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332
4333drop:
4334 kfree_skb(skb);
4335
4336done:
Marcel Holtmann01394182006-07-03 10:02:46 +02004337 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004338 release_sock(sk);
Marcel Holtmann01394182006-07-03 10:02:46 +02004339
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 return 0;
4341}
4342
Al Viro8e036fc2007-07-29 00:16:36 -07004343static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004345 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004346 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004348 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4349 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 goto drop;
4351
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004352 sk = chan->sk;
4353
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004354 lock_sock(sk);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00004355
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 BT_DBG("sk %p, len %d", sk, skb->len);
4357
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004358 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 goto drop;
4360
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004361 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 goto drop;
4363
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004364 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 goto done;
4366
4367drop:
4368 kfree_skb(skb);
4369
4370done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004371 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004372 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 return 0;
4374}
4375
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004376static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4377{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004378 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004379 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004380
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004381 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4382 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004383 goto drop;
4384
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004385 sk = chan->sk;
4386
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004387 lock_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004388
4389 BT_DBG("sk %p, len %d", sk, skb->len);
4390
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004391 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004392 goto drop;
4393
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004394 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004395 goto drop;
4396
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004397 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004398 goto done;
4399
4400drop:
4401 kfree_skb(skb);
4402
4403done:
4404 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004405 release_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004406 return 0;
4407}
4408
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4410{
4411 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004412 u16 cid, len;
4413 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414
4415 skb_pull(skb, L2CAP_HDR_SIZE);
4416 cid = __le16_to_cpu(lh->cid);
4417 len = __le16_to_cpu(lh->len);
4418
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004419 if (len != skb->len) {
4420 kfree_skb(skb);
4421 return;
4422 }
4423
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4425
4426 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004427 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004428 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 l2cap_sig_channel(conn, skb);
4430 break;
4431
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004432 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004433 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 skb_pull(skb, 2);
4435 l2cap_conless_channel(conn, psm, skb);
4436 break;
4437
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004438 case L2CAP_CID_LE_DATA:
4439 l2cap_att_channel(conn, cid, skb);
4440 break;
4441
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004442 case L2CAP_CID_SMP:
4443 if (smp_sig_channel(conn, skb))
4444 l2cap_conn_del(conn->hcon, EACCES);
4445 break;
4446
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 default:
4448 l2cap_data_channel(conn, cid, skb);
4449 break;
4450 }
4451}
4452
4453/* ---- L2CAP interface with lower layer (HCI) ---- */
4454
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004455int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456{
4457 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004458 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4461
4462 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004463 read_lock(&chan_list_lock);
4464 list_for_each_entry(c, &chan_list, global_l) {
4465 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004466
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004467 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 continue;
4469
4470 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004471 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004472 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004473 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004475 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4476 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004477 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004478 lm2 |= HCI_LM_MASTER;
4479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004481 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482
4483 return exact ? lm1 : lm2;
4484}
4485
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004486int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487{
Marcel Holtmann01394182006-07-03 10:02:46 +02004488 struct l2cap_conn *conn;
4489
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4491
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 conn = l2cap_conn_add(hcon, status);
4494 if (conn)
4495 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004496 } else
Joe Perchese1750722011-06-29 18:18:29 -07004497 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498
4499 return 0;
4500}
4501
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004502int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004503{
4504 struct l2cap_conn *conn = hcon->l2cap_data;
4505
4506 BT_DBG("hcon %p", hcon);
4507
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004508 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004509 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004510 return conn->disc_reason;
4511}
4512
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004513int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514{
4515 BT_DBG("hcon %p reason %d", hcon, reason);
4516
Joe Perchese1750722011-06-29 18:18:29 -07004517 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 return 0;
4519}
4520
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004521static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004522{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004523 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004524 return;
4525
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004526 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004527 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004528 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004529 __set_chan_timer(chan,
4530 msecs_to_jiffies(L2CAP_ENC_TIMEOUT));
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004531 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004532 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004533 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004534 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004535 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004536 }
4537}
4538
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004539int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004541 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004542 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543
Marcel Holtmann01394182006-07-03 10:02:46 +02004544 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004545 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004546
Linus Torvalds1da177e2005-04-16 15:20:36 -07004547 BT_DBG("conn %p", conn);
4548
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004549 if (hcon->type == LE_LINK) {
4550 smp_distribute_keys(conn, 0);
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02004551 cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004552 }
4553
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004554 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004556 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004557 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004558
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 bh_lock_sock(sk);
4560
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004561 BT_DBG("chan->scid %d", chan->scid);
4562
4563 if (chan->scid == L2CAP_CID_LE_DATA) {
4564 if (!status && encrypt) {
4565 chan->sec_level = hcon->sec_level;
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02004566 l2cap_chan_ready(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004567 }
4568
4569 bh_unlock_sock(sk);
4570 continue;
4571 }
4572
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004573 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004574 bh_unlock_sock(sk);
4575 continue;
4576 }
4577
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004578 if (!status && (chan->state == BT_CONNECTED ||
4579 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004580 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004581 bh_unlock_sock(sk);
4582 continue;
4583 }
4584
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004585 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004586 if (!status) {
4587 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004588 req.scid = cpu_to_le16(chan->scid);
4589 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004590
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004591 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004592 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004593
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004594 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004595 L2CAP_CONN_REQ, sizeof(req), &req);
4596 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004597 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004598 __set_chan_timer(chan,
4599 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004600 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004601 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004602 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004603 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004604
4605 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004606 if (bt_sk(sk)->defer_setup) {
4607 struct sock *parent = bt_sk(sk)->parent;
4608 res = L2CAP_CR_PEND;
4609 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004610 if (parent)
4611 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004612 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004613 __l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004614 res = L2CAP_CR_SUCCESS;
4615 stat = L2CAP_CS_NO_INFO;
4616 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004617 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004618 __l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004619 __set_chan_timer(chan,
4620 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004621 res = L2CAP_CR_SEC_BLOCK;
4622 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004623 }
4624
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004625 rsp.scid = cpu_to_le16(chan->dcid);
4626 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004627 rsp.result = cpu_to_le16(res);
4628 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004629 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4630 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 }
4632
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 bh_unlock_sock(sk);
4634 }
4635
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004636 mutex_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004637
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 return 0;
4639}
4640
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004641int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642{
4643 struct l2cap_conn *conn = hcon->l2cap_data;
4644
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004645 if (!conn)
4646 conn = l2cap_conn_add(hcon, 0);
4647
4648 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 goto drop;
4650
4651 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4652
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004653 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004655 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004656 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 int len;
4658
4659 if (conn->rx_len) {
4660 BT_ERR("Unexpected start frame (len %d)", skb->len);
4661 kfree_skb(conn->rx_skb);
4662 conn->rx_skb = NULL;
4663 conn->rx_len = 0;
4664 l2cap_conn_unreliable(conn, ECOMM);
4665 }
4666
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004667 /* Start fragment always begin with Basic L2CAP header */
4668 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 BT_ERR("Frame is too short (len %d)", skb->len);
4670 l2cap_conn_unreliable(conn, ECOMM);
4671 goto drop;
4672 }
4673
4674 hdr = (struct l2cap_hdr *) skb->data;
4675 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004676 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677
4678 if (len == skb->len) {
4679 /* Complete frame received */
4680 l2cap_recv_frame(conn, skb);
4681 return 0;
4682 }
4683
4684 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4685
4686 if (skb->len > len) {
4687 BT_ERR("Frame is too long (len %d, expected len %d)",
4688 skb->len, len);
4689 l2cap_conn_unreliable(conn, ECOMM);
4690 goto drop;
4691 }
4692
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004693 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004694
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004695 if (chan && chan->sk) {
4696 struct sock *sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004697 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004698
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004699 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004700 BT_ERR("Frame exceeding recv MTU (len %d, "
4701 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004702 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004703 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004704 l2cap_conn_unreliable(conn, ECOMM);
4705 goto drop;
4706 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004707 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004708 }
4709
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004711 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4712 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 goto drop;
4714
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004715 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004716 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 conn->rx_len = len - skb->len;
4718 } else {
4719 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4720
4721 if (!conn->rx_len) {
4722 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4723 l2cap_conn_unreliable(conn, ECOMM);
4724 goto drop;
4725 }
4726
4727 if (skb->len > conn->rx_len) {
4728 BT_ERR("Fragment is too long (len %d, expected %d)",
4729 skb->len, conn->rx_len);
4730 kfree_skb(conn->rx_skb);
4731 conn->rx_skb = NULL;
4732 conn->rx_len = 0;
4733 l2cap_conn_unreliable(conn, ECOMM);
4734 goto drop;
4735 }
4736
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004737 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004738 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739 conn->rx_len -= skb->len;
4740
4741 if (!conn->rx_len) {
4742 /* Complete frame received */
4743 l2cap_recv_frame(conn, conn->rx_skb);
4744 conn->rx_skb = NULL;
4745 }
4746 }
4747
4748drop:
4749 kfree_skb(skb);
4750 return 0;
4751}
4752
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004753static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004755 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004757 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004759 list_for_each_entry(c, &chan_list, global_l) {
4760 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004762 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 +01004763 batostr(&bt_sk(sk)->src),
4764 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004765 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004766 c->scid, c->dcid, c->imtu, c->omtu,
4767 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004768 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004770 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004771
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004772 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773}
4774
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004775static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4776{
4777 return single_open(file, l2cap_debugfs_show, inode->i_private);
4778}
4779
4780static const struct file_operations l2cap_debugfs_fops = {
4781 .open = l2cap_debugfs_open,
4782 .read = seq_read,
4783 .llseek = seq_lseek,
4784 .release = single_release,
4785};
4786
4787static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004788
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004789int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790{
4791 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004792
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004793 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 if (err < 0)
4795 return err;
4796
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004797 if (bt_debugfs) {
4798 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4799 bt_debugfs, NULL, &l2cap_debugfs_fops);
4800 if (!l2cap_debugfs)
4801 BT_ERR("Failed to create L2CAP debug file");
4802 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805}
4806
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004807void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004809 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004810 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811}
4812
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004813module_param(disable_ertm, bool, 0644);
4814MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");