blob: 0b1aabff8649f5202a7d7ee1c9b364d7c05c13c9 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Gustavo F. Padovan590051d2011-12-18 13:39:33 -02006 Copyright (C) 2011 ProFUSION Embedded Systems
Linus Torvalds1da177e2005-04-16 15:20:36 -07007
8 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation;
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
17 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090023 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 SOFTWARE IS DISCLAIMED.
26*/
27
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020028/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31
32#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080033#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/errno.h>
35#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/sched.h>
37#include <linux/slab.h>
38#include <linux/poll.h>
39#include <linux/fcntl.h>
40#include <linux/init.h>
41#include <linux/interrupt.h>
42#include <linux/socket.h>
43#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080045#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010046#include <linux/debugfs.h>
47#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030048#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030049#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <net/sock.h>
51
52#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <asm/unaligned.h>
54
55#include <net/bluetooth/bluetooth.h>
56#include <net/bluetooth/hci_core.h>
57#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030058#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Rusty Russelleb939922011-12-19 14:08:01 +000060bool disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020061
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070062static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070063static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Johannes Bergb5ad8b72011-06-01 08:54:45 +020065static LIST_HEAD(chan_list);
66static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
69 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030070static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
71 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030072static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030073static void l2cap_send_disconn_req(struct l2cap_conn *conn,
74 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Marcel Holtmann01394182006-07-03 10:02:46 +020076/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030077
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030078static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020079{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020080 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030081
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020082 list_for_each_entry(c, &conn->chan_l, list) {
83 if (c->dcid == cid)
84 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020085 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020086 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020087}
88
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030089static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020090{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020091 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030092
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020093 list_for_each_entry(c, &conn->chan_l, list) {
94 if (c->scid == cid)
95 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020096 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020097 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020098}
99
100/* Find channel with given SCID.
101 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300102static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200103{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300104 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300105
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200106 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300107 c = __l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200108 mutex_unlock(&conn->chan_lock);
109
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300110 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200111}
112
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300113static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200114{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200115 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300116
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200117 list_for_each_entry(c, &conn->chan_l, list) {
118 if (c->ident == ident)
119 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200120 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200121 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200122}
123
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300124static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200125{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300126 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300127
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200128 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300129 c = __l2cap_get_chan_by_ident(conn, ident);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200130 mutex_unlock(&conn->chan_lock);
131
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300132 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200133}
134
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300135static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300136{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300137 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300138
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300139 list_for_each_entry(c, &chan_list, global_l) {
140 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100141 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300142 }
Szymon Janc250938c2011-11-16 09:32:22 +0100143 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300144}
145
146int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
147{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300148 int err;
149
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200150 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300151
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300152 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300153 err = -EADDRINUSE;
154 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300155 }
156
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300157 if (psm) {
158 chan->psm = psm;
159 chan->sport = psm;
160 err = 0;
161 } else {
162 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300163
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300164 err = -EINVAL;
165 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300166 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300167 chan->psm = cpu_to_le16(p);
168 chan->sport = cpu_to_le16(p);
169 err = 0;
170 break;
171 }
172 }
173
174done:
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200175 write_unlock(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300176 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300177}
178
179int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
180{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200181 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300182
183 chan->scid = scid;
184
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200185 write_unlock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300186
187 return 0;
188}
189
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300190static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200191{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300192 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200193
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300194 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300195 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200196 return cid;
197 }
198
199 return 0;
200}
201
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200202static void __l2cap_state_change(struct l2cap_chan *chan, int state)
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300203{
Andrei Emeltchenko42d2d872012-02-17 11:40:57 +0200204 BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200205 state_to_string(state));
206
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300207 chan->state = state;
208 chan->ops->state_change(chan->data, state);
209}
210
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200211static void l2cap_state_change(struct l2cap_chan *chan, int state)
212{
213 struct sock *sk = chan->sk;
214
215 lock_sock(sk);
216 __l2cap_state_change(chan, state);
217 release_sock(sk);
218}
219
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200220static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
221{
222 struct sock *sk = chan->sk;
223
224 sk->sk_err = err;
225}
226
227static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
228{
229 struct sock *sk = chan->sk;
230
231 lock_sock(sk);
232 __l2cap_chan_set_err(chan, err);
233 release_sock(sk);
234}
235
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300236static void l2cap_chan_timeout(struct work_struct *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300237{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300238 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
239 chan_timer.work);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200240 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300241 int reason;
242
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200243 BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300244
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200245 mutex_lock(&conn->chan_lock);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200246 l2cap_chan_lock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300247
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300248 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300249 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300250 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300251 chan->sec_level != BT_SECURITY_SDP)
252 reason = ECONNREFUSED;
253 else
254 reason = ETIMEDOUT;
255
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300256 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300257
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200258 l2cap_chan_unlock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300259
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300260 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200261 mutex_unlock(&conn->chan_lock);
262
Ulisses Furquim371fd832011-12-21 20:02:36 -0200263 l2cap_chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300264}
265
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300266struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200267{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300268 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200269
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300270 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
271 if (!chan)
272 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200273
Andrei Emeltchenkoc03b3552012-02-21 12:54:56 +0200274 mutex_init(&chan->lock);
275
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300276 chan->sk = sk;
277
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200278 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300279 list_add(&chan->global_l, &chan_list);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200280 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300281
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300282 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300283
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300284 chan->state = BT_OPEN;
285
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300286 atomic_set(&chan->refcnt, 1);
287
Szymon Jancabc545b2011-11-03 16:05:44 +0100288 BT_DBG("sk %p chan %p", sk, chan);
289
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300290 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200291}
292
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300293void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300294{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200295 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300296 list_del(&chan->global_l);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200297 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300298
Ulisses Furquim371fd832011-12-21 20:02:36 -0200299 l2cap_chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300300}
301
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200302void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200303{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300304 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300305 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200306
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200307 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100308
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300309 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200310
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200311 switch (chan->chan_type) {
312 case L2CAP_CHAN_CONN_ORIENTED:
Ville Tervob62f3282011-02-10 22:38:50 -0300313 if (conn->hcon->type == LE_LINK) {
314 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300315 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300316 chan->scid = L2CAP_CID_LE_DATA;
317 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300318 } else {
319 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300320 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300321 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300322 }
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200323 break;
324
325 case L2CAP_CHAN_CONN_LESS:
Marcel Holtmann01394182006-07-03 10:02:46 +0200326 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300327 chan->scid = L2CAP_CID_CONN_LESS;
328 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300329 chan->omtu = L2CAP_DEFAULT_MTU;
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200330 break;
331
332 default:
Marcel Holtmann01394182006-07-03 10:02:46 +0200333 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300334 chan->scid = L2CAP_CID_SIGNALING;
335 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300336 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200337 }
338
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300339 chan->local_id = L2CAP_BESTEFFORT_ID;
340 chan->local_stype = L2CAP_SERV_BESTEFFORT;
341 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
342 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
343 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
344 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
345
Ulisses Furquim371fd832011-12-21 20:02:36 -0200346 l2cap_chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300347
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200348 list_add(&chan->list, &conn->chan_l);
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200349}
350
351void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
352{
353 mutex_lock(&conn->chan_lock);
354 __l2cap_chan_add(conn, chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200355 mutex_unlock(&conn->chan_lock);
Marcel Holtmann01394182006-07-03 10:02:46 +0200356}
357
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300358static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200359{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300360 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300361 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200362 struct sock *parent = bt_sk(sk)->parent;
363
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300364 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200365
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300366 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200367
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900368 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300369 /* Delete from channel list */
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200370 list_del(&chan->list);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200371
Ulisses Furquim371fd832011-12-21 20:02:36 -0200372 l2cap_chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300373
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300374 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200375 hci_conn_put(conn->hcon);
376 }
377
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200378 lock_sock(sk);
379
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200380 __l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200381 sock_set_flag(sk, SOCK_ZAPPED);
382
383 if (err)
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200384 __l2cap_chan_set_err(chan, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200385
386 if (parent) {
387 bt_accept_unlink(sk);
388 parent->sk_data_ready(parent, 0);
389 } else
390 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300391
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200392 release_sock(sk);
393
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300394 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
395 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300396 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300397
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300398 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300399
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300400 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300401 struct srej_list *l, *tmp;
402
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300403 __clear_retrans_timer(chan);
404 __clear_monitor_timer(chan);
405 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300406
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300407 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300408
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300409 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300410 list_del(&l->list);
411 kfree(l);
412 }
413 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200414}
415
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300416static void l2cap_chan_cleanup_listen(struct sock *parent)
417{
418 struct sock *sk;
419
420 BT_DBG("parent %p", parent);
421
422 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300423 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300424 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200425
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200426 l2cap_chan_lock(chan);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300427 __clear_chan_timer(chan);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300428 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200429 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200430
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300431 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300432 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300433}
434
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300435void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300436{
437 struct l2cap_conn *conn = chan->conn;
438 struct sock *sk = chan->sk;
439
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200440 BT_DBG("chan %p state %s sk %p", chan,
441 state_to_string(chan->state), sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300442
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300443 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300444 case BT_LISTEN:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200445 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300446 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300447
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200448 __l2cap_state_change(chan, BT_CLOSED);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300449 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200450 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300451 break;
452
453 case BT_CONNECTED:
454 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300455 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300456 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300457 __clear_chan_timer(chan);
458 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300459 l2cap_send_disconn_req(conn, chan, reason);
460 } else
461 l2cap_chan_del(chan, reason);
462 break;
463
464 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300465 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300466 conn->hcon->type == ACL_LINK) {
467 struct l2cap_conn_rsp rsp;
468 __u16 result;
469
470 if (bt_sk(sk)->defer_setup)
471 result = L2CAP_CR_SEC_BLOCK;
472 else
473 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300474 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300475
476 rsp.scid = cpu_to_le16(chan->dcid);
477 rsp.dcid = cpu_to_le16(chan->scid);
478 rsp.result = cpu_to_le16(result);
479 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
480 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
481 sizeof(rsp), &rsp);
482 }
483
484 l2cap_chan_del(chan, reason);
485 break;
486
487 case BT_CONNECT:
488 case BT_DISCONN:
489 l2cap_chan_del(chan, reason);
490 break;
491
492 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200493 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300494 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200495 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300496 break;
497 }
498}
499
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300500static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530501{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300502 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300503 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530504 case BT_SECURITY_HIGH:
505 return HCI_AT_DEDICATED_BONDING_MITM;
506 case BT_SECURITY_MEDIUM:
507 return HCI_AT_DEDICATED_BONDING;
508 default:
509 return HCI_AT_NO_BONDING;
510 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300511 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300512 if (chan->sec_level == BT_SECURITY_LOW)
513 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530514
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300515 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530516 return HCI_AT_NO_BONDING_MITM;
517 else
518 return HCI_AT_NO_BONDING;
519 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300520 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530521 case BT_SECURITY_HIGH:
522 return HCI_AT_GENERAL_BONDING_MITM;
523 case BT_SECURITY_MEDIUM:
524 return HCI_AT_GENERAL_BONDING;
525 default:
526 return HCI_AT_NO_BONDING;
527 }
528 }
529}
530
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200531/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200532int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200533{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300534 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100535 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200536
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300537 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100538
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300539 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200540}
541
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200542static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200543{
544 u8 id;
545
546 /* Get next available identificator.
547 * 1 - 128 are used by kernel.
548 * 129 - 199 are reserved.
549 * 200 - 254 are used by utilities like l2ping, etc.
550 */
551
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200552 spin_lock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200553
554 if (++conn->tx_ident > 128)
555 conn->tx_ident = 1;
556
557 id = conn->tx_ident;
558
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200559 spin_unlock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200560
561 return id;
562}
563
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300564static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200565{
566 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200567 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200568
569 BT_DBG("code 0x%2.2x", code);
570
571 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300572 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200573
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200574 if (lmp_no_flush_capable(conn->hcon->hdev))
575 flags = ACL_START_NO_FLUSH;
576 else
577 flags = ACL_START;
578
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700579 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200580 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700581
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200582 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200583}
584
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200585static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
586{
587 struct hci_conn *hcon = chan->conn->hcon;
588 u16 flags;
589
590 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
591 skb->priority);
592
593 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
594 lmp_no_flush_capable(hcon->hdev))
595 flags = ACL_START_NO_FLUSH;
596 else
597 flags = ACL_START;
598
599 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
600 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601}
602
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300603static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300604{
605 struct sk_buff *skb;
606 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300607 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300608 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300609
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300610 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300611 return;
612
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300613 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
614 hlen = L2CAP_EXT_HDR_SIZE;
615 else
616 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300617
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300618 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300619 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300620
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300621 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300622
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300623 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300624
625 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300626
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300627 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300628 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300629
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300630 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300631 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300632
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300633 skb = bt_skb_alloc(count, GFP_ATOMIC);
634 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300635 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300636
637 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300638 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300639 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300640
641 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300642
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300643 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300644 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
645 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300646 }
647
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200648 skb->priority = HCI_PRIO_MAX;
649 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300650}
651
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300652static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300653{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300654 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300655 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300656 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300657 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300658 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300659
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300660 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300661
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300662 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300663}
664
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300665static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300666{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300667 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300668}
669
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200670static void l2cap_send_conn_req(struct l2cap_chan *chan)
671{
672 struct l2cap_conn *conn = chan->conn;
673 struct l2cap_conn_req req;
674
675 req.scid = cpu_to_le16(chan->scid);
676 req.psm = chan->psm;
677
678 chan->ident = l2cap_get_ident(conn);
679
680 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
681
682 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
683}
684
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300685static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200686{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300687 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200688
689 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100690 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
691 return;
692
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200693 if (l2cap_chan_check_security(chan) &&
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200694 __l2cap_no_conn_pending(chan))
695 l2cap_send_conn_req(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200696 } else {
697 struct l2cap_info_req req;
698 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
699
700 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
701 conn->info_ident = l2cap_get_ident(conn);
702
Marcel Holtmannba13ccd2012-03-01 14:25:33 -0800703 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200704
705 l2cap_send_cmd(conn, conn->info_ident,
706 L2CAP_INFO_REQ, sizeof(req), &req);
707 }
708}
709
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300710static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
711{
712 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300713 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300714 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
715
716 switch (mode) {
717 case L2CAP_MODE_ERTM:
718 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
719 case L2CAP_MODE_STREAMING:
720 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
721 default:
722 return 0x00;
723 }
724}
725
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300726static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300727{
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200728 struct sock *sk = chan->sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300729 struct l2cap_disconn_req req;
730
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300731 if (!conn)
732 return;
733
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300734 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300735 __clear_retrans_timer(chan);
736 __clear_monitor_timer(chan);
737 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300738 }
739
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300740 req.dcid = cpu_to_le16(chan->dcid);
741 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300742 l2cap_send_cmd(conn, l2cap_get_ident(conn),
743 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300744
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200745 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200746 __l2cap_state_change(chan, BT_DISCONN);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200747 __l2cap_chan_set_err(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200748 release_sock(sk);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300749}
750
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200752static void l2cap_conn_start(struct l2cap_conn *conn)
753{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200754 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200755
756 BT_DBG("conn %p", conn);
757
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200758 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200759
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200760 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300761 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300762
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200763 l2cap_chan_lock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200764
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300765 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200766 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200767 continue;
768 }
769
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300770 if (chan->state == BT_CONNECT) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200771 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300772 !__l2cap_no_conn_pending(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200773 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300774 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200775 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300776
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300777 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
778 && test_bit(CONF_STATE2_DEVICE,
779 &chan->conf_state)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300780 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200781 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300782 continue;
783 }
784
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200785 l2cap_send_conn_req(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300786
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300787 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200788 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300789 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300790 rsp.scid = cpu_to_le16(chan->dcid);
791 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200792
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200793 if (l2cap_chan_check_security(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200794 lock_sock(sk);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100795 if (bt_sk(sk)->defer_setup) {
796 struct sock *parent = bt_sk(sk)->parent;
797 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
798 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000799 if (parent)
800 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100801
802 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200803 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100804 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
805 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
806 }
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200807 release_sock(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200808 } else {
809 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
810 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
811 }
812
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300813 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
814 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300815
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300816 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300817 rsp.result != L2CAP_CR_SUCCESS) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200818 l2cap_chan_unlock(chan);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300819 continue;
820 }
821
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300822 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300823 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300824 l2cap_build_conf_req(chan, buf), buf);
825 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200826 }
827
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200828 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200829 }
830
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200831 mutex_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200832}
833
Ville Tervob62f3282011-02-10 22:38:50 -0300834/* Find socket with cid and source bdaddr.
835 * Returns closest match, locked.
836 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300837static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300838{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300839 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300840
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300841 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300842
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300843 list_for_each_entry(c, &chan_list, global_l) {
844 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300845
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300846 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300847 continue;
848
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300849 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300850 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300851 if (!bacmp(&bt_sk(sk)->src, src)) {
852 read_unlock(&chan_list_lock);
853 return c;
854 }
Ville Tervob62f3282011-02-10 22:38:50 -0300855
856 /* Closest match */
857 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300858 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300859 }
860 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300861
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300862 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300863
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300864 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300865}
866
867static void l2cap_le_conn_ready(struct l2cap_conn *conn)
868{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300869 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300870 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300871
872 BT_DBG("");
873
874 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300875 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300876 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300877 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300878 return;
879
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300880 parent = pchan->sk;
881
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300882 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300883
Ville Tervob62f3282011-02-10 22:38:50 -0300884 /* Check for backlog size */
885 if (sk_acceptq_is_full(parent)) {
886 BT_DBG("backlog full %d", parent->sk_ack_backlog);
887 goto clean;
888 }
889
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300890 chan = pchan->ops->new_connection(pchan->data);
891 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300892 goto clean;
893
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300894 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300895
Ville Tervob62f3282011-02-10 22:38:50 -0300896 hci_conn_hold(conn->hcon);
897
Ville Tervob62f3282011-02-10 22:38:50 -0300898 bacpy(&bt_sk(sk)->src, conn->src);
899 bacpy(&bt_sk(sk)->dst, conn->dst);
900
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300901 bt_accept_enqueue(parent, sk);
902
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200903 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300904
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300905 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300906
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200907 __l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300908 parent->sk_data_ready(parent, 0);
909
Ville Tervob62f3282011-02-10 22:38:50 -0300910clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300911 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300912}
913
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200914static void l2cap_chan_ready(struct l2cap_chan *chan)
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300915{
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200916 struct sock *sk = chan->sk;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200917 struct sock *parent;
918
919 lock_sock(sk);
920
921 parent = bt_sk(sk)->parent;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300922
923 BT_DBG("sk %p, parent %p", sk, parent);
924
925 chan->conf_state = 0;
926 __clear_chan_timer(chan);
927
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200928 __l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300929 sk->sk_state_change(sk);
930
931 if (parent)
932 parent->sk_data_ready(parent, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200933
934 release_sock(sk);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300935}
936
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200937static void l2cap_conn_ready(struct l2cap_conn *conn)
938{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300939 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200940
941 BT_DBG("conn %p", conn);
942
Ville Tervob62f3282011-02-10 22:38:50 -0300943 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
944 l2cap_le_conn_ready(conn);
945
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300946 if (conn->hcon->out && conn->hcon->type == LE_LINK)
947 smp_conn_security(conn, conn->hcon->pending_sec_level);
948
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200949 mutex_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200950
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200951 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300952
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200953 l2cap_chan_lock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200954
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300955 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300956 if (smp_conn_security(conn, chan->sec_level))
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200957 l2cap_chan_ready(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300958
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300959 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200960 struct sock *sk = chan->sk;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300961 __clear_chan_timer(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200962 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200963 __l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200964 sk->sk_state_change(sk);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200965 release_sock(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300966
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300967 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300968 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200969
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200970 l2cap_chan_unlock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200971 }
972
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200973 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200974}
975
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200976/* Notify sockets that we cannot guaranty reliability anymore */
977static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
978{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300979 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200980
981 BT_DBG("conn %p", conn);
982
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200983 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200984
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200985 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300986 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200987 __l2cap_chan_set_err(chan, err);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200988 }
989
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200990 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200991}
992
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200993static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200994{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200995 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200996 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200997
Marcel Holtmann984947d2009-02-06 23:35:19 +0100998 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100999 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01001000
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001001 l2cap_conn_start(conn);
1002}
1003
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001004static void l2cap_conn_del(struct hci_conn *hcon, int err)
1005{
1006 struct l2cap_conn *conn = hcon->l2cap_data;
1007 struct l2cap_chan *chan, *l;
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001008
1009 if (!conn)
1010 return;
1011
1012 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1013
1014 kfree_skb(conn->rx_skb);
1015
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001016 mutex_lock(&conn->chan_lock);
1017
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001018 /* Kill channels */
1019 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001020 l2cap_chan_lock(chan);
1021
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001022 l2cap_chan_del(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001023
1024 l2cap_chan_unlock(chan);
1025
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001026 chan->ops->close(chan->data);
1027 }
1028
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001029 mutex_unlock(&conn->chan_lock);
1030
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001031 hci_chan_del(conn->hchan);
1032
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001033 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim127074b2012-01-30 18:26:29 -02001034 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001035
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001036 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim127074b2012-01-30 18:26:29 -02001037 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001038 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001039 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001040
1041 hcon->l2cap_data = NULL;
1042 kfree(conn);
1043}
1044
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001045static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001046{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001047 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1048 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001049
1050 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1051}
1052
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1054{
Marcel Holtmann01394182006-07-03 10:02:46 +02001055 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001056 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Marcel Holtmann01394182006-07-03 10:02:46 +02001058 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 return conn;
1060
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001061 hchan = hci_chan_create(hcon);
1062 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001065 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1066 if (!conn) {
1067 hci_chan_del(hchan);
1068 return NULL;
1069 }
1070
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 hcon->l2cap_data = conn;
1072 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001073 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001075 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001076
Ville Tervoacd7d372011-02-10 22:38:49 -03001077 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1078 conn->mtu = hcon->hdev->le_mtu;
1079 else
1080 conn->mtu = hcon->hdev->acl_mtu;
1081
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 conn->src = &hcon->hdev->bdaddr;
1083 conn->dst = &hcon->dst;
1084
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001085 conn->feat_mask = 0;
1086
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 spin_lock_init(&conn->lock);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001088 mutex_init(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001089
1090 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001092 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001093 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001094 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001095 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001096
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001097 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001098
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 return conn;
1100}
1101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104/* Find socket with psm and source bdaddr.
1105 * Returns closest match.
1106 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001107static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001109 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001111 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001112
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001113 list_for_each_entry(c, &chan_list, global_l) {
1114 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001115
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001116 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 continue;
1118
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001119 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001121 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001122 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001123 return c;
1124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126 /* Closest match */
1127 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001128 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 }
1130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001132 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001133
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001134 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135}
1136
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001137int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001139 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 struct l2cap_conn *conn;
1142 struct hci_conn *hcon;
1143 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001144 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001145 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001147 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001148 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001150 hdev = hci_get_route(dst, src);
1151 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 return -EHOSTUNREACH;
1153
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001154 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001156 l2cap_chan_lock(chan);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001157
1158 /* PSM must be odd and lsb of upper byte must be 0 */
1159 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1160 chan->chan_type != L2CAP_CHAN_RAW) {
1161 err = -EINVAL;
1162 goto done;
1163 }
1164
1165 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1166 err = -EINVAL;
1167 goto done;
1168 }
1169
1170 switch (chan->mode) {
1171 case L2CAP_MODE_BASIC:
1172 break;
1173 case L2CAP_MODE_ERTM:
1174 case L2CAP_MODE_STREAMING:
1175 if (!disable_ertm)
1176 break;
1177 /* fall through */
1178 default:
1179 err = -ENOTSUPP;
1180 goto done;
1181 }
1182
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001183 lock_sock(sk);
1184
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001185 switch (sk->sk_state) {
1186 case BT_CONNECT:
1187 case BT_CONNECT2:
1188 case BT_CONFIG:
1189 /* Already connecting */
1190 err = 0;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001191 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001192 goto done;
1193
1194 case BT_CONNECTED:
1195 /* Already connected */
1196 err = -EISCONN;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001197 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001198 goto done;
1199
1200 case BT_OPEN:
1201 case BT_BOUND:
1202 /* Can connect */
1203 break;
1204
1205 default:
1206 err = -EBADFD;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001207 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001208 goto done;
1209 }
1210
1211 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001212 bacpy(&bt_sk(sk)->dst, dst);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001213
1214 release_sock(sk);
1215
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001216 chan->psm = psm;
1217 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001219 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001220
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001221 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001222 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001223 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001224 else
1225 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001226 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001227
Ville Tervo30e76272011-02-22 16:10:53 -03001228 if (IS_ERR(hcon)) {
1229 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 conn = l2cap_conn_add(hcon, 0);
1234 if (!conn) {
1235 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001236 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 goto done;
1238 }
1239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 /* Update source addr of the socket */
1241 bacpy(src, conn->src);
1242
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001243 l2cap_chan_unlock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001244 l2cap_chan_add(conn, chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001245 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001246
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001247 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001248 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001251 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001252 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001253 if (l2cap_chan_check_security(chan))
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001254 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001255 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001256 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 }
1258
Ville Tervo30e76272011-02-22 16:10:53 -03001259 err = 0;
1260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001262 l2cap_chan_unlock(chan);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001263 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 hci_dev_put(hdev);
1265 return err;
1266}
1267
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001268int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001269{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001270 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001271 DECLARE_WAITQUEUE(wait, current);
1272 int err = 0;
1273 int timeo = HZ/5;
1274
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001275 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001276 set_current_state(TASK_INTERRUPTIBLE);
1277 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001278 if (!timeo)
1279 timeo = HZ/5;
1280
1281 if (signal_pending(current)) {
1282 err = sock_intr_errno(timeo);
1283 break;
1284 }
1285
1286 release_sock(sk);
1287 timeo = schedule_timeout(timeo);
1288 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001289 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001290
1291 err = sock_error(sk);
1292 if (err)
1293 break;
1294 }
1295 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001296 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001297 return err;
1298}
1299
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001300static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001301{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001302 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1303 monitor_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001304
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001305 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001306
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001307 l2cap_chan_lock(chan);
1308
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001309 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001310 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001311 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001312 return;
1313 }
1314
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001315 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001316 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001317
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001318 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001319 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001320}
1321
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001322static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001323{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001324 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1325 retrans_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001326
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001327 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001328
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001329 l2cap_chan_lock(chan);
1330
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001331 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001332 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001333
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001334 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001335
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001336 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001337
1338 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001339}
1340
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001341static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001342{
1343 struct sk_buff *skb;
1344
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001345 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001346 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001347 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001348 break;
1349
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001350 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001351 kfree_skb(skb);
1352
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001353 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001354 }
1355
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001356 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001357 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001358}
1359
Szymon Janc67c9e842011-07-28 16:24:33 +02001360static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001361{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001362 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001363 u32 control;
1364 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001365
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001366 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001367 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001368 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001369 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001370
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001371 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001372 fcs = crc16(0, (u8 *)skb->data,
1373 skb->len - L2CAP_FCS_SIZE);
1374 put_unaligned_le16(fcs,
1375 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001376 }
1377
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001378 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001379
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001380 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001381 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001382}
1383
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001384static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001385{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001386 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001387 u16 fcs;
1388 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001389
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001390 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001391 if (!skb)
1392 return;
1393
Szymon Jancd1726b62011-11-16 09:32:20 +01001394 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001395 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001396 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001397
Szymon Jancd1726b62011-11-16 09:32:20 +01001398 skb = skb_queue_next(&chan->tx_q, skb);
1399 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001400
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001401 if (chan->remote_max_tx &&
1402 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001403 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001404 return;
1405 }
1406
1407 tx_skb = skb_clone(skb, GFP_ATOMIC);
1408 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001409
1410 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001411 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001412
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001413 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001414 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001415
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001416 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001417 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001418
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001419 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001420
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001421 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001422 fcs = crc16(0, (u8 *)tx_skb->data,
1423 tx_skb->len - L2CAP_FCS_SIZE);
1424 put_unaligned_le16(fcs,
1425 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001426 }
1427
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001428 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001429}
1430
Szymon Janc67c9e842011-07-28 16:24:33 +02001431static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001432{
1433 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001434 u16 fcs;
1435 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001436 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001437
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001438 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001439 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001440
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001441 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001442
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001443 if (chan->remote_max_tx &&
1444 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001445 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001446 break;
1447 }
1448
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001449 tx_skb = skb_clone(skb, GFP_ATOMIC);
1450
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001451 bt_cb(skb)->retries++;
1452
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001453 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001454 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001455
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001456 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001457 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001458
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001459 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001460 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001461
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001462 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001463
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001464 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001465 fcs = crc16(0, (u8 *)skb->data,
1466 tx_skb->len - L2CAP_FCS_SIZE);
1467 put_unaligned_le16(fcs, skb->data +
1468 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001469 }
1470
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001471 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001472
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001473 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001474
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001475 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001476
1477 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001478
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001479 if (bt_cb(skb)->retries == 1) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001480 chan->unacked_frames++;
Szymon Janc930fa4a2012-02-07 15:43:02 +01001481
1482 if (!nsent++)
1483 __clear_ack_timer(chan);
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001484 }
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301485
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001486 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001487
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001488 if (skb_queue_is_last(&chan->tx_q, skb))
1489 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001490 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001491 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001492 }
1493
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001494 return nsent;
1495}
1496
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001497static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001498{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001499 int ret;
1500
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001501 if (!skb_queue_empty(&chan->tx_q))
1502 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001503
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001504 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001505 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001506 return ret;
1507}
1508
Szymon Jancb17e73b2012-01-11 10:59:47 +01001509static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001510{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001511 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001512
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001513 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001514
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001515 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001516 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001517 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001518 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001519 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001520 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001521
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001522 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001523 return;
1524
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001525 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001526 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001527}
1528
Szymon Jancb17e73b2012-01-11 10:59:47 +01001529static void l2cap_send_ack(struct l2cap_chan *chan)
1530{
1531 __clear_ack_timer(chan);
1532 __l2cap_send_ack(chan);
1533}
1534
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001535static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001536{
1537 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001538 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001539
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001540 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001541 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001542
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001543 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001544 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001545
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001546 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001547}
1548
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001549static 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 -07001550{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001551 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001552 struct sk_buff **frag;
1553 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001555 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001556 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557
1558 sent += count;
1559 len -= count;
1560
1561 /* Continuation fragments (no L2CAP header) */
1562 frag = &skb_shinfo(skb)->frag_list;
1563 while (len) {
1564 count = min_t(unsigned int, conn->mtu, len);
1565
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001566 *frag = chan->ops->alloc_skb(chan, count,
1567 msg->msg_flags & MSG_DONTWAIT, &err);
1568
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001570 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001571 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1572 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001574 (*frag)->priority = skb->priority;
1575
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576 sent += count;
1577 len -= count;
1578
1579 frag = &(*frag)->next;
1580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581
1582 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001583}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001585static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1586 struct msghdr *msg, size_t len,
1587 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001588{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001589 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001590 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001591 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001592 struct l2cap_hdr *lh;
1593
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001594 BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001595
1596 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001597
1598 skb = chan->ops->alloc_skb(chan, count + hlen,
1599 msg->msg_flags & MSG_DONTWAIT, &err);
1600
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001601 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001602 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001603
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001604 skb->priority = priority;
1605
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001606 /* Create L2CAP header */
1607 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001608 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001609 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001610 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001611
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001612 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001613 if (unlikely(err < 0)) {
1614 kfree_skb(skb);
1615 return ERR_PTR(err);
1616 }
1617 return skb;
1618}
1619
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001620static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1621 struct msghdr *msg, size_t len,
1622 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001623{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001624 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001625 struct sk_buff *skb;
1626 int err, count, hlen = L2CAP_HDR_SIZE;
1627 struct l2cap_hdr *lh;
1628
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001629 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001630
1631 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001632
1633 skb = chan->ops->alloc_skb(chan, count + hlen,
1634 msg->msg_flags & MSG_DONTWAIT, &err);
1635
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001636 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001637 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001638
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001639 skb->priority = priority;
1640
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001641 /* Create L2CAP header */
1642 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001643 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001644 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1645
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001646 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001647 if (unlikely(err < 0)) {
1648 kfree_skb(skb);
1649 return ERR_PTR(err);
1650 }
1651 return skb;
1652}
1653
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001654static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1655 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001656 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001657{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001658 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001659 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001660 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001661 struct l2cap_hdr *lh;
1662
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001663 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001664
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001665 if (!conn)
1666 return ERR_PTR(-ENOTCONN);
1667
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001668 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1669 hlen = L2CAP_EXT_HDR_SIZE;
1670 else
1671 hlen = L2CAP_ENH_HDR_SIZE;
1672
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001673 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001674 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001675
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001676 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001677 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001678
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001679 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001680
1681 skb = chan->ops->alloc_skb(chan, count + hlen,
1682 msg->msg_flags & MSG_DONTWAIT, &err);
1683
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001684 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001685 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001686
1687 /* Create L2CAP header */
1688 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001689 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001690 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001691
1692 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1693
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001694 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001695 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001696
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001697 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001698 if (unlikely(err < 0)) {
1699 kfree_skb(skb);
1700 return ERR_PTR(err);
1701 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001702
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001703 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001704 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001705
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001706 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001707 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708}
1709
Szymon Janc67c9e842011-07-28 16:24:33 +02001710static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001711{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001712 struct sk_buff *skb;
1713 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001714 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001715 size_t size = 0;
1716
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001717 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001718 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001719 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001720 if (IS_ERR(skb))
1721 return PTR_ERR(skb);
1722
1723 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001724 len -= chan->remote_mps;
1725 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001726
1727 while (len > 0) {
1728 size_t buflen;
1729
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001730 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001731 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001732 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001733 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001734 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001735 buflen = len;
1736 }
1737
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001738 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001739 if (IS_ERR(skb)) {
1740 skb_queue_purge(&sar_queue);
1741 return PTR_ERR(skb);
1742 }
1743
1744 __skb_queue_tail(&sar_queue, skb);
1745 len -= buflen;
1746 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001747 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001748 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1749 if (chan->tx_send_head == NULL)
1750 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001751
1752 return size;
1753}
1754
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001755int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1756 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001757{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001758 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001759 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001760 int err;
1761
1762 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001763 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001764 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001765 if (IS_ERR(skb))
1766 return PTR_ERR(skb);
1767
1768 l2cap_do_send(chan, skb);
1769 return len;
1770 }
1771
1772 switch (chan->mode) {
1773 case L2CAP_MODE_BASIC:
1774 /* Check outgoing MTU */
1775 if (len > chan->omtu)
1776 return -EMSGSIZE;
1777
1778 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001779 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001780 if (IS_ERR(skb))
1781 return PTR_ERR(skb);
1782
1783 l2cap_do_send(chan, skb);
1784 err = len;
1785 break;
1786
1787 case L2CAP_MODE_ERTM:
1788 case L2CAP_MODE_STREAMING:
1789 /* Entire SDU fits into one PDU */
1790 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001791 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001792 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1793 0);
1794 if (IS_ERR(skb))
1795 return PTR_ERR(skb);
1796
1797 __skb_queue_tail(&chan->tx_q, skb);
1798
1799 if (chan->tx_send_head == NULL)
1800 chan->tx_send_head = skb;
1801
1802 } else {
1803 /* Segment SDU into multiples PDUs */
1804 err = l2cap_sar_segment_sdu(chan, msg, len);
1805 if (err < 0)
1806 return err;
1807 }
1808
1809 if (chan->mode == L2CAP_MODE_STREAMING) {
1810 l2cap_streaming_send(chan);
1811 err = len;
1812 break;
1813 }
1814
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001815 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1816 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001817 err = len;
1818 break;
1819 }
1820
1821 err = l2cap_ertm_send(chan);
1822 if (err >= 0)
1823 err = len;
1824
1825 break;
1826
1827 default:
1828 BT_DBG("bad state %1.1x", chan->mode);
1829 err = -EBADFD;
1830 }
1831
1832 return err;
1833}
1834
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835/* Copy frame to all raw sockets on that connection */
1836static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1837{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001839 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840
1841 BT_DBG("conn %p", conn);
1842
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001843 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001844
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001845 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001846 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001847 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 continue;
1849
1850 /* Don't send frame to the socket it came from */
1851 if (skb->sk == sk)
1852 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001853 nskb = skb_clone(skb, GFP_ATOMIC);
1854 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 continue;
1856
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001857 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 kfree_skb(nskb);
1859 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001860
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001861 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862}
1863
1864/* ---- L2CAP signalling commands ---- */
1865static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1866 u8 code, u8 ident, u16 dlen, void *data)
1867{
1868 struct sk_buff *skb, **frag;
1869 struct l2cap_cmd_hdr *cmd;
1870 struct l2cap_hdr *lh;
1871 int len, count;
1872
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001873 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1874 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875
1876 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1877 count = min_t(unsigned int, conn->mtu, len);
1878
1879 skb = bt_skb_alloc(count, GFP_ATOMIC);
1880 if (!skb)
1881 return NULL;
1882
1883 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001884 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001885
1886 if (conn->hcon->type == LE_LINK)
1887 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1888 else
1889 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
1891 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1892 cmd->code = code;
1893 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001894 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
1896 if (dlen) {
1897 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1898 memcpy(skb_put(skb, count), data, count);
1899 data += count;
1900 }
1901
1902 len -= skb->len;
1903
1904 /* Continuation fragments (no L2CAP header) */
1905 frag = &skb_shinfo(skb)->frag_list;
1906 while (len) {
1907 count = min_t(unsigned int, conn->mtu, len);
1908
1909 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1910 if (!*frag)
1911 goto fail;
1912
1913 memcpy(skb_put(*frag, count), data, count);
1914
1915 len -= count;
1916 data += count;
1917
1918 frag = &(*frag)->next;
1919 }
1920
1921 return skb;
1922
1923fail:
1924 kfree_skb(skb);
1925 return NULL;
1926}
1927
1928static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1929{
1930 struct l2cap_conf_opt *opt = *ptr;
1931 int len;
1932
1933 len = L2CAP_CONF_OPT_SIZE + opt->len;
1934 *ptr += len;
1935
1936 *type = opt->type;
1937 *olen = opt->len;
1938
1939 switch (opt->len) {
1940 case 1:
1941 *val = *((u8 *) opt->val);
1942 break;
1943
1944 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001945 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 break;
1947
1948 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001949 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 break;
1951
1952 default:
1953 *val = (unsigned long) opt->val;
1954 break;
1955 }
1956
1957 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1958 return len;
1959}
1960
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1962{
1963 struct l2cap_conf_opt *opt = *ptr;
1964
1965 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1966
1967 opt->type = type;
1968 opt->len = len;
1969
1970 switch (len) {
1971 case 1:
1972 *((u8 *) opt->val) = val;
1973 break;
1974
1975 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001976 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 break;
1978
1979 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001980 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 break;
1982
1983 default:
1984 memcpy(opt->val, (void *) val, len);
1985 break;
1986 }
1987
1988 *ptr += L2CAP_CONF_OPT_SIZE + len;
1989}
1990
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001991static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1992{
1993 struct l2cap_conf_efs efs;
1994
Szymon Janc1ec918c2011-11-16 09:32:21 +01001995 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001996 case L2CAP_MODE_ERTM:
1997 efs.id = chan->local_id;
1998 efs.stype = chan->local_stype;
1999 efs.msdu = cpu_to_le16(chan->local_msdu);
2000 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2001 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
2002 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
2003 break;
2004
2005 case L2CAP_MODE_STREAMING:
2006 efs.id = 1;
2007 efs.stype = L2CAP_SERV_BESTEFFORT;
2008 efs.msdu = cpu_to_le16(chan->local_msdu);
2009 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2010 efs.acc_lat = 0;
2011 efs.flush_to = 0;
2012 break;
2013
2014 default:
2015 return;
2016 }
2017
2018 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
2019 (unsigned long) &efs);
2020}
2021
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002022static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002023{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002024 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2025 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002026
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02002027 BT_DBG("chan %p", chan);
2028
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002029 l2cap_chan_lock(chan);
2030
Szymon Jancb17e73b2012-01-11 10:59:47 +01002031 __l2cap_send_ack(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002032
2033 l2cap_chan_unlock(chan);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002034
2035 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002036}
2037
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002038static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002039{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002040 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002041 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002042 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002043 chan->num_acked = 0;
2044 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002045
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002046 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2047 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2048 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002049
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002050 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002051
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002052 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002053}
2054
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002055static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2056{
2057 switch (mode) {
2058 case L2CAP_MODE_STREAMING:
2059 case L2CAP_MODE_ERTM:
2060 if (l2cap_mode_supported(mode, remote_feat_mask))
2061 return mode;
2062 /* fall through */
2063 default:
2064 return L2CAP_MODE_BASIC;
2065 }
2066}
2067
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002068static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2069{
2070 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2071}
2072
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002073static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2074{
2075 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2076}
2077
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002078static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2079{
2080 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002081 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002082 /* use extended control field */
2083 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002084 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2085 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002086 chan->tx_win = min_t(u16, chan->tx_win,
2087 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002088 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2089 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002090}
2091
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002092static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002095 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002097 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002099 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002101 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002102 goto done;
2103
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002104 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002105 case L2CAP_MODE_STREAMING:
2106 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002107 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002108 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002109
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002110 if (__l2cap_efs_supported(chan))
2111 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2112
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002113 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002114 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002115 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002116 break;
2117 }
2118
2119done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002120 if (chan->imtu != L2CAP_DEFAULT_MTU)
2121 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002122
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002123 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002124 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002125 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2126 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002127 break;
2128
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002129 rfc.mode = L2CAP_MODE_BASIC;
2130 rfc.txwin_size = 0;
2131 rfc.max_transmit = 0;
2132 rfc.retrans_timeout = 0;
2133 rfc.monitor_timeout = 0;
2134 rfc.max_pdu_size = 0;
2135
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002136 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2137 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002138 break;
2139
2140 case L2CAP_MODE_ERTM:
2141 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002142 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002143 rfc.retrans_timeout = 0;
2144 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002145
2146 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2147 L2CAP_EXT_HDR_SIZE -
2148 L2CAP_SDULEN_SIZE -
2149 L2CAP_FCS_SIZE);
2150 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002151
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002152 l2cap_txwin_setup(chan);
2153
2154 rfc.txwin_size = min_t(u16, chan->tx_win,
2155 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002156
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002157 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2158 (unsigned long) &rfc);
2159
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002160 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2161 l2cap_add_opt_efs(&ptr, chan);
2162
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002163 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002164 break;
2165
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002166 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002167 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002168 chan->fcs = L2CAP_FCS_NONE;
2169 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002170 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002171
2172 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2173 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2174 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002175 break;
2176
2177 case L2CAP_MODE_STREAMING:
2178 rfc.mode = L2CAP_MODE_STREAMING;
2179 rfc.txwin_size = 0;
2180 rfc.max_transmit = 0;
2181 rfc.retrans_timeout = 0;
2182 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002183
2184 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2185 L2CAP_EXT_HDR_SIZE -
2186 L2CAP_SDULEN_SIZE -
2187 L2CAP_FCS_SIZE);
2188 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002189
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002190 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2191 (unsigned long) &rfc);
2192
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002193 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2194 l2cap_add_opt_efs(&ptr, chan);
2195
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002196 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002197 break;
2198
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002199 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002200 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002201 chan->fcs = L2CAP_FCS_NONE;
2202 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002203 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002204 break;
2205 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002207 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002208 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
2210 return ptr - data;
2211}
2212
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002213static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002215 struct l2cap_conf_rsp *rsp = data;
2216 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002217 void *req = chan->conf_req;
2218 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002219 int type, hint, olen;
2220 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002221 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002222 struct l2cap_conf_efs efs;
2223 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002224 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002225 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002226 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002228 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002229
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002230 while (len >= L2CAP_CONF_OPT_SIZE) {
2231 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002233 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002234 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002235
2236 switch (type) {
2237 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002238 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002239 break;
2240
2241 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002242 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002243 break;
2244
2245 case L2CAP_CONF_QOS:
2246 break;
2247
Marcel Holtmann6464f352007-10-20 13:39:51 +02002248 case L2CAP_CONF_RFC:
2249 if (olen == sizeof(rfc))
2250 memcpy(&rfc, (void *) val, olen);
2251 break;
2252
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002253 case L2CAP_CONF_FCS:
2254 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002255 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002256 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002257
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002258 case L2CAP_CONF_EFS:
2259 remote_efs = 1;
2260 if (olen == sizeof(efs))
2261 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002262 break;
2263
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002264 case L2CAP_CONF_EWS:
2265 if (!enable_hs)
2266 return -ECONNREFUSED;
2267
2268 set_bit(FLAG_EXT_CTRL, &chan->flags);
2269 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002270 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002271 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002272 break;
2273
2274 default:
2275 if (hint)
2276 break;
2277
2278 result = L2CAP_CONF_UNKNOWN;
2279 *((u8 *) ptr++) = type;
2280 break;
2281 }
2282 }
2283
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002284 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002285 goto done;
2286
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002287 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002288 case L2CAP_MODE_STREAMING:
2289 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002290 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002291 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002292 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002293 break;
2294 }
2295
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002296 if (remote_efs) {
2297 if (__l2cap_efs_supported(chan))
2298 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2299 else
2300 return -ECONNREFUSED;
2301 }
2302
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002303 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002304 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002305
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002306 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002307 }
2308
2309done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002310 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002311 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002312 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002313
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002314 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002315 return -ECONNREFUSED;
2316
2317 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2318 sizeof(rfc), (unsigned long) &rfc);
2319 }
2320
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002321 if (result == L2CAP_CONF_SUCCESS) {
2322 /* Configure output options and let the other side know
2323 * which ones we don't like. */
2324
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002325 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2326 result = L2CAP_CONF_UNACCEPT;
2327 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002328 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002329 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002330 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002331 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002332
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002333 if (remote_efs) {
2334 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2335 efs.stype != L2CAP_SERV_NOTRAFIC &&
2336 efs.stype != chan->local_stype) {
2337
2338 result = L2CAP_CONF_UNACCEPT;
2339
2340 if (chan->num_conf_req >= 1)
2341 return -ECONNREFUSED;
2342
2343 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002344 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002345 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002346 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002347 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002348 result = L2CAP_CONF_PENDING;
2349 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002350 }
2351 }
2352
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002353 switch (rfc.mode) {
2354 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002355 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002356 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002357 break;
2358
2359 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002360 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2361 chan->remote_tx_win = rfc.txwin_size;
2362 else
2363 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2364
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002365 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002366
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002367 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2368 chan->conn->mtu -
2369 L2CAP_EXT_HDR_SIZE -
2370 L2CAP_SDULEN_SIZE -
2371 L2CAP_FCS_SIZE);
2372 rfc.max_pdu_size = cpu_to_le16(size);
2373 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002374
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002375 rfc.retrans_timeout =
2376 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2377 rfc.monitor_timeout =
2378 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002379
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002380 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002381
2382 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2383 sizeof(rfc), (unsigned long) &rfc);
2384
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002385 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2386 chan->remote_id = efs.id;
2387 chan->remote_stype = efs.stype;
2388 chan->remote_msdu = le16_to_cpu(efs.msdu);
2389 chan->remote_flush_to =
2390 le32_to_cpu(efs.flush_to);
2391 chan->remote_acc_lat =
2392 le32_to_cpu(efs.acc_lat);
2393 chan->remote_sdu_itime =
2394 le32_to_cpu(efs.sdu_itime);
2395 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2396 sizeof(efs), (unsigned long) &efs);
2397 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002398 break;
2399
2400 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002401 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2402 chan->conn->mtu -
2403 L2CAP_EXT_HDR_SIZE -
2404 L2CAP_SDULEN_SIZE -
2405 L2CAP_FCS_SIZE);
2406 rfc.max_pdu_size = cpu_to_le16(size);
2407 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002408
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002409 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002410
2411 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2412 sizeof(rfc), (unsigned long) &rfc);
2413
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002414 break;
2415
2416 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002417 result = L2CAP_CONF_UNACCEPT;
2418
2419 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002420 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002421 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002422
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002423 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002424 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002425 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002426 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002427 rsp->result = cpu_to_le16(result);
2428 rsp->flags = cpu_to_le16(0x0000);
2429
2430 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431}
2432
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002433static 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 -03002434{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002435 struct l2cap_conf_req *req = data;
2436 void *ptr = req->data;
2437 int type, olen;
2438 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002439 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002440 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002441
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002442 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002443
2444 while (len >= L2CAP_CONF_OPT_SIZE) {
2445 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2446
2447 switch (type) {
2448 case L2CAP_CONF_MTU:
2449 if (val < L2CAP_DEFAULT_MIN_MTU) {
2450 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002451 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002452 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002453 chan->imtu = val;
2454 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002455 break;
2456
2457 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002458 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002459 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002460 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002461 break;
2462
2463 case L2CAP_CONF_RFC:
2464 if (olen == sizeof(rfc))
2465 memcpy(&rfc, (void *)val, olen);
2466
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002467 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002468 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002469 return -ECONNREFUSED;
2470
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002471 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002472
2473 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2474 sizeof(rfc), (unsigned long) &rfc);
2475 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002476
2477 case L2CAP_CONF_EWS:
2478 chan->tx_win = min_t(u16, val,
2479 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002480 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2481 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002482 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002483
2484 case L2CAP_CONF_EFS:
2485 if (olen == sizeof(efs))
2486 memcpy(&efs, (void *)val, olen);
2487
2488 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2489 efs.stype != L2CAP_SERV_NOTRAFIC &&
2490 efs.stype != chan->local_stype)
2491 return -ECONNREFUSED;
2492
2493 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2494 sizeof(efs), (unsigned long) &efs);
2495 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002496 }
2497 }
2498
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002499 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002500 return -ECONNREFUSED;
2501
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002502 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002503
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002504 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002505 switch (rfc.mode) {
2506 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002507 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2508 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2509 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002510
2511 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2512 chan->local_msdu = le16_to_cpu(efs.msdu);
2513 chan->local_sdu_itime =
2514 le32_to_cpu(efs.sdu_itime);
2515 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2516 chan->local_flush_to =
2517 le32_to_cpu(efs.flush_to);
2518 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002519 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002520
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002521 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002522 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002523 }
2524 }
2525
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002526 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002527 req->flags = cpu_to_le16(0x0000);
2528
2529 return ptr - data;
2530}
2531
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002532static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533{
2534 struct l2cap_conf_rsp *rsp = data;
2535 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002537 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002539 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002540 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002541 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
2543 return ptr - data;
2544}
2545
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002546void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002547{
2548 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002549 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002550 u8 buf[128];
2551
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002552 rsp.scid = cpu_to_le16(chan->dcid);
2553 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002554 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2555 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2556 l2cap_send_cmd(conn, chan->ident,
2557 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2558
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002559 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002560 return;
2561
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002562 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2563 l2cap_build_conf_req(chan, buf), buf);
2564 chan->num_conf_req++;
2565}
2566
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002567static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002568{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002569 int type, olen;
2570 unsigned long val;
2571 struct l2cap_conf_rfc rfc;
2572
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002573 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002574
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002575 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002576 return;
2577
2578 while (len >= L2CAP_CONF_OPT_SIZE) {
2579 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2580
2581 switch (type) {
2582 case L2CAP_CONF_RFC:
2583 if (olen == sizeof(rfc))
2584 memcpy(&rfc, (void *)val, olen);
2585 goto done;
2586 }
2587 }
2588
Mat Martineau36e999a2011-12-08 17:23:21 -08002589 /* Use sane default values in case a misbehaving remote device
2590 * did not send an RFC option.
2591 */
2592 rfc.mode = chan->mode;
2593 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2594 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2595 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2596
2597 BT_ERR("Expected RFC option was not found, using defaults");
2598
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002599done:
2600 switch (rfc.mode) {
2601 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002602 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2603 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2604 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002605 break;
2606 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002607 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002608 }
2609}
2610
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002611static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2612{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002613 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002614
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002615 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002616 return 0;
2617
2618 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2619 cmd->ident == conn->info_ident) {
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02002620 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002621
2622 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002623 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002624
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002625 l2cap_conn_start(conn);
2626 }
2627
2628 return 0;
2629}
2630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2632{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2634 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002635 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002636 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002637 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638
2639 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002640 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641
2642 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2643
2644 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002645 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2646 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 result = L2CAP_CR_BAD_PSM;
2648 goto sendresp;
2649 }
2650
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002651 parent = pchan->sk;
2652
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002653 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002654 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002655
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002656 /* Check if the ACL is secure enough (if not SDP) */
2657 if (psm != cpu_to_le16(0x0001) &&
2658 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002659 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002660 result = L2CAP_CR_SEC_BLOCK;
2661 goto response;
2662 }
2663
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 result = L2CAP_CR_NO_MEM;
2665
2666 /* Check for backlog size */
2667 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002668 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 goto response;
2670 }
2671
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002672 chan = pchan->ops->new_connection(pchan->data);
2673 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 goto response;
2675
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002676 sk = chan->sk;
2677
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002679 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002681 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 goto response;
2683 }
2684
2685 hci_conn_hold(conn->hcon);
2686
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 bacpy(&bt_sk(sk)->src, conn->src);
2688 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002689 chan->psm = psm;
2690 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002692 bt_accept_enqueue(parent, sk);
2693
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002694 __l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002695
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002696 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002698 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002700 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701
Marcel Holtmann984947d2009-02-06 23:35:19 +01002702 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002703 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002704 if (bt_sk(sk)->defer_setup) {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002705 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002706 result = L2CAP_CR_PEND;
2707 status = L2CAP_CS_AUTHOR_PEND;
2708 parent->sk_data_ready(parent, 0);
2709 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002710 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002711 result = L2CAP_CR_SUCCESS;
2712 status = L2CAP_CS_NO_INFO;
2713 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002714 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002715 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002716 result = L2CAP_CR_PEND;
2717 status = L2CAP_CS_AUTHEN_PEND;
2718 }
2719 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002720 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002721 result = L2CAP_CR_PEND;
2722 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 }
2724
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002726 release_sock(parent);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002727 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
2729sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002730 rsp.scid = cpu_to_le16(scid);
2731 rsp.dcid = cpu_to_le16(dcid);
2732 rsp.result = cpu_to_le16(result);
2733 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002735
2736 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2737 struct l2cap_info_req info;
2738 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2739
2740 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2741 conn->info_ident = l2cap_get_ident(conn);
2742
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08002743 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002744
2745 l2cap_send_cmd(conn, conn->info_ident,
2746 L2CAP_INFO_REQ, sizeof(info), &info);
2747 }
2748
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002749 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002750 result == L2CAP_CR_SUCCESS) {
2751 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002752 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002753 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002754 l2cap_build_conf_req(chan, buf), buf);
2755 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002756 }
2757
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 return 0;
2759}
2760
2761static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2762{
2763 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2764 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002765 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 u8 req[128];
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002767 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768
2769 scid = __le16_to_cpu(rsp->scid);
2770 dcid = __le16_to_cpu(rsp->dcid);
2771 result = __le16_to_cpu(rsp->result);
2772 status = __le16_to_cpu(rsp->status);
2773
Andrei Emeltchenko1b009c92012-02-21 12:54:54 +02002774 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
2775 dcid, scid, result, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002777 mutex_lock(&conn->chan_lock);
2778
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 if (scid) {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002780 chan = __l2cap_get_chan_by_scid(conn, scid);
2781 if (!chan) {
2782 err = -EFAULT;
2783 goto unlock;
2784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 } else {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002786 chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
2787 if (!chan) {
2788 err = -EFAULT;
2789 goto unlock;
2790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 }
2792
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002793 err = 0;
2794
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002795 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002796
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 switch (result) {
2798 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002799 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002800 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002801 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002802 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002803
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002804 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002805 break;
2806
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002808 l2cap_build_conf_req(chan, req), req);
2809 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 break;
2811
2812 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002813 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 break;
2815
2816 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002817 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 break;
2819 }
2820
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002821 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002822
2823unlock:
2824 mutex_unlock(&conn->chan_lock);
2825
2826 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827}
2828
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002829static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002830{
2831 /* FCS is enabled only in ERTM or streaming mode, if one or both
2832 * sides request it.
2833 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002834 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002835 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002836 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002837 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002838}
2839
Al Viro88219a02007-07-29 00:17:25 -07002840static 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 -07002841{
2842 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2843 u16 dcid, flags;
2844 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002845 struct l2cap_chan *chan;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002846 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847
2848 dcid = __le16_to_cpu(req->dcid);
2849 flags = __le16_to_cpu(req->flags);
2850
2851 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2852
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002853 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002854 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 return -ENOENT;
2856
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002857 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002858
David S. Miller033b1142011-07-21 13:38:42 -07002859 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002860 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002861
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002862 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2863 rej.scid = cpu_to_le16(chan->scid);
2864 rej.dcid = cpu_to_le16(chan->dcid);
2865
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002866 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2867 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002868 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002869 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002870
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002871 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002872 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002873 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002874 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002875 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002876 L2CAP_CONF_REJECT, flags), rsp);
2877 goto unlock;
2878 }
2879
2880 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002881 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2882 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883
2884 if (flags & 0x0001) {
2885 /* Incomplete config. Send empty response. */
2886 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002887 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002888 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889 goto unlock;
2890 }
2891
2892 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002893 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002894 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002895 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002899 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002900 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002901
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002902 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002903 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002904
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002905 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002906 goto unlock;
2907
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002908 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002909 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002910
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002911 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002912
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002913 chan->next_tx_seq = 0;
2914 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002915 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002916 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002917 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002918
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02002919 l2cap_chan_ready(chan);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002920 goto unlock;
2921 }
2922
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002923 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002924 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002926 l2cap_build_conf_req(chan, buf), buf);
2927 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 }
2929
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002930 /* Got Conf Rsp PENDING from remote side and asume we sent
2931 Conf Rsp PENDING in the code above */
2932 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2933 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2934
2935 /* check compatibility */
2936
2937 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2938 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2939
2940 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002941 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002942 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2943 }
2944
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945unlock:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002946 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 return 0;
2948}
2949
2950static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2951{
2952 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2953 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002954 struct l2cap_chan *chan;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002955 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956
2957 scid = __le16_to_cpu(rsp->scid);
2958 flags = __le16_to_cpu(rsp->flags);
2959 result = __le16_to_cpu(rsp->result);
2960
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002961 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2962 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002964 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002965 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 return 0;
2967
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002968 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002969
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 switch (result) {
2971 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002972 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002973 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 break;
2975
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002976 case L2CAP_CONF_PENDING:
2977 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2978
2979 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2980 char buf[64];
2981
2982 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2983 buf, &result);
2984 if (len < 0) {
2985 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2986 goto done;
2987 }
2988
2989 /* check compatibility */
2990
2991 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2992 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2993
2994 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002995 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002996 L2CAP_CONF_SUCCESS, 0x0000), buf);
2997 }
2998 goto done;
2999
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003001 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003002 char req[64];
3003
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003004 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003005 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003006 goto done;
3007 }
3008
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003009 /* throw out any old stored conf requests */
3010 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03003011 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
3012 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003013 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003014 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003015 goto done;
3016 }
3017
3018 l2cap_send_cmd(conn, l2cap_get_ident(conn),
3019 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003020 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003021 if (result != L2CAP_CONF_SUCCESS)
3022 goto done;
3023 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 }
3025
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09003026 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003027 l2cap_chan_set_err(chan, ECONNRESET);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +02003028
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08003029 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003030 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 goto done;
3032 }
3033
3034 if (flags & 0x01)
3035 goto done;
3036
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003037 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003039 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003040 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003041
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003042 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003043 chan->next_tx_seq = 0;
3044 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003045 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003046 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003047 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003048
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02003049 l2cap_chan_ready(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 }
3051
3052done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003053 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 return 0;
3055}
3056
3057static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3058{
3059 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3060 struct l2cap_disconn_rsp rsp;
3061 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003062 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 struct sock *sk;
3064
3065 scid = __le16_to_cpu(req->scid);
3066 dcid = __le16_to_cpu(req->dcid);
3067
3068 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3069
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003070 mutex_lock(&conn->chan_lock);
3071
3072 chan = __l2cap_get_chan_by_scid(conn, dcid);
3073 if (!chan) {
3074 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003075 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003078 l2cap_chan_lock(chan);
3079
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003080 sk = chan->sk;
3081
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003082 rsp.dcid = cpu_to_le16(chan->scid);
3083 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3085
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003086 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 sk->sk_shutdown = SHUTDOWN_MASK;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003088 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003090 l2cap_chan_del(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003091
3092 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003094 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003095
3096 mutex_unlock(&conn->chan_lock);
3097
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 return 0;
3099}
3100
3101static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3102{
3103 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3104 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003105 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003106
3107 scid = __le16_to_cpu(rsp->scid);
3108 dcid = __le16_to_cpu(rsp->dcid);
3109
3110 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3111
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003112 mutex_lock(&conn->chan_lock);
3113
3114 chan = __l2cap_get_chan_by_scid(conn, scid);
3115 if (!chan) {
3116 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003120 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003121
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003122 l2cap_chan_del(chan, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003123
3124 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003126 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003127
3128 mutex_unlock(&conn->chan_lock);
3129
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 return 0;
3131}
3132
3133static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3134{
3135 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 u16 type;
3137
3138 type = __le16_to_cpu(req->type);
3139
3140 BT_DBG("type 0x%4.4x", type);
3141
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003142 if (type == L2CAP_IT_FEAT_MASK) {
3143 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003144 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003145 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3146 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3147 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003148 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003149 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3150 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003151 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003152 feat_mask |= L2CAP_FEAT_EXT_FLOW
3153 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003154
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003155 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003156 l2cap_send_cmd(conn, cmd->ident,
3157 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003158 } else if (type == L2CAP_IT_FIXED_CHAN) {
3159 u8 buf[12];
3160 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003161
3162 if (enable_hs)
3163 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3164 else
3165 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3166
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003167 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3168 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003169 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003170 l2cap_send_cmd(conn, cmd->ident,
3171 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003172 } else {
3173 struct l2cap_info_rsp rsp;
3174 rsp.type = cpu_to_le16(type);
3175 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3176 l2cap_send_cmd(conn, cmd->ident,
3177 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
3180 return 0;
3181}
3182
3183static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3184{
3185 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3186 u16 type, result;
3187
3188 type = __le16_to_cpu(rsp->type);
3189 result = __le16_to_cpu(rsp->result);
3190
3191 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3192
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003193 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3194 if (cmd->ident != conn->info_ident ||
3195 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3196 return 0;
3197
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02003198 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003199
Ville Tervoadb08ed2010-08-04 09:43:33 +03003200 if (result != L2CAP_IR_SUCCESS) {
3201 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3202 conn->info_ident = 0;
3203
3204 l2cap_conn_start(conn);
3205
3206 return 0;
3207 }
3208
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003209 switch (type) {
3210 case L2CAP_IT_FEAT_MASK:
Harvey Harrison83985312008-05-02 16:25:46 -07003211 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003212
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003213 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003214 struct l2cap_info_req req;
3215 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3216
3217 conn->info_ident = l2cap_get_ident(conn);
3218
3219 l2cap_send_cmd(conn, conn->info_ident,
3220 L2CAP_INFO_REQ, sizeof(req), &req);
3221 } else {
3222 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3223 conn->info_ident = 0;
3224
3225 l2cap_conn_start(conn);
3226 }
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003227 break;
3228
3229 case L2CAP_IT_FIXED_CHAN:
3230 conn->fixed_chan_mask = rsp->data[0];
Marcel Holtmann984947d2009-02-06 23:35:19 +01003231 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003232 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003233
3234 l2cap_conn_start(conn);
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003235 break;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003236 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003237
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 return 0;
3239}
3240
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003241static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3242 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3243 void *data)
3244{
3245 struct l2cap_create_chan_req *req = data;
3246 struct l2cap_create_chan_rsp rsp;
3247 u16 psm, scid;
3248
3249 if (cmd_len != sizeof(*req))
3250 return -EPROTO;
3251
3252 if (!enable_hs)
3253 return -EINVAL;
3254
3255 psm = le16_to_cpu(req->psm);
3256 scid = le16_to_cpu(req->scid);
3257
3258 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3259
3260 /* Placeholder: Always reject */
3261 rsp.dcid = 0;
3262 rsp.scid = cpu_to_le16(scid);
3263 rsp.result = L2CAP_CR_NO_MEM;
3264 rsp.status = L2CAP_CS_NO_INFO;
3265
3266 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3267 sizeof(rsp), &rsp);
3268
3269 return 0;
3270}
3271
3272static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3273 struct l2cap_cmd_hdr *cmd, void *data)
3274{
3275 BT_DBG("conn %p", conn);
3276
3277 return l2cap_connect_rsp(conn, cmd, data);
3278}
3279
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003280static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3281 u16 icid, u16 result)
3282{
3283 struct l2cap_move_chan_rsp rsp;
3284
3285 BT_DBG("icid %d, result %d", icid, result);
3286
3287 rsp.icid = cpu_to_le16(icid);
3288 rsp.result = cpu_to_le16(result);
3289
3290 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3291}
3292
3293static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3294 struct l2cap_chan *chan, u16 icid, u16 result)
3295{
3296 struct l2cap_move_chan_cfm cfm;
3297 u8 ident;
3298
3299 BT_DBG("icid %d, result %d", icid, result);
3300
3301 ident = l2cap_get_ident(conn);
3302 if (chan)
3303 chan->ident = ident;
3304
3305 cfm.icid = cpu_to_le16(icid);
3306 cfm.result = cpu_to_le16(result);
3307
3308 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3309}
3310
3311static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3312 u16 icid)
3313{
3314 struct l2cap_move_chan_cfm_rsp rsp;
3315
3316 BT_DBG("icid %d", icid);
3317
3318 rsp.icid = cpu_to_le16(icid);
3319 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3320}
3321
3322static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3323 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3324{
3325 struct l2cap_move_chan_req *req = data;
3326 u16 icid = 0;
3327 u16 result = L2CAP_MR_NOT_ALLOWED;
3328
3329 if (cmd_len != sizeof(*req))
3330 return -EPROTO;
3331
3332 icid = le16_to_cpu(req->icid);
3333
3334 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3335
3336 if (!enable_hs)
3337 return -EINVAL;
3338
3339 /* Placeholder: Always refuse */
3340 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3341
3342 return 0;
3343}
3344
3345static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3346 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3347{
3348 struct l2cap_move_chan_rsp *rsp = data;
3349 u16 icid, result;
3350
3351 if (cmd_len != sizeof(*rsp))
3352 return -EPROTO;
3353
3354 icid = le16_to_cpu(rsp->icid);
3355 result = le16_to_cpu(rsp->result);
3356
3357 BT_DBG("icid %d, result %d", icid, result);
3358
3359 /* Placeholder: Always unconfirmed */
3360 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3361
3362 return 0;
3363}
3364
3365static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3366 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3367{
3368 struct l2cap_move_chan_cfm *cfm = data;
3369 u16 icid, result;
3370
3371 if (cmd_len != sizeof(*cfm))
3372 return -EPROTO;
3373
3374 icid = le16_to_cpu(cfm->icid);
3375 result = le16_to_cpu(cfm->result);
3376
3377 BT_DBG("icid %d, result %d", icid, result);
3378
3379 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3380
3381 return 0;
3382}
3383
3384static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3385 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3386{
3387 struct l2cap_move_chan_cfm_rsp *rsp = data;
3388 u16 icid;
3389
3390 if (cmd_len != sizeof(*rsp))
3391 return -EPROTO;
3392
3393 icid = le16_to_cpu(rsp->icid);
3394
3395 BT_DBG("icid %d", icid);
3396
3397 return 0;
3398}
3399
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003400static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003401 u16 to_multiplier)
3402{
3403 u16 max_latency;
3404
3405 if (min > max || min < 6 || max > 3200)
3406 return -EINVAL;
3407
3408 if (to_multiplier < 10 || to_multiplier > 3200)
3409 return -EINVAL;
3410
3411 if (max >= to_multiplier * 8)
3412 return -EINVAL;
3413
3414 max_latency = (to_multiplier * 8 / max) - 1;
3415 if (latency > 499 || latency > max_latency)
3416 return -EINVAL;
3417
3418 return 0;
3419}
3420
3421static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3422 struct l2cap_cmd_hdr *cmd, u8 *data)
3423{
3424 struct hci_conn *hcon = conn->hcon;
3425 struct l2cap_conn_param_update_req *req;
3426 struct l2cap_conn_param_update_rsp rsp;
3427 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003428 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003429
3430 if (!(hcon->link_mode & HCI_LM_MASTER))
3431 return -EINVAL;
3432
3433 cmd_len = __le16_to_cpu(cmd->len);
3434 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3435 return -EPROTO;
3436
3437 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003438 min = __le16_to_cpu(req->min);
3439 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003440 latency = __le16_to_cpu(req->latency);
3441 to_multiplier = __le16_to_cpu(req->to_multiplier);
3442
3443 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3444 min, max, latency, to_multiplier);
3445
3446 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003447
3448 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3449 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003450 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3451 else
3452 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3453
3454 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3455 sizeof(rsp), &rsp);
3456
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003457 if (!err)
3458 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3459
Claudio Takahaside731152011-02-11 19:28:55 -02003460 return 0;
3461}
3462
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003463static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3464 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3465{
3466 int err = 0;
3467
3468 switch (cmd->code) {
3469 case L2CAP_COMMAND_REJ:
3470 l2cap_command_rej(conn, cmd, data);
3471 break;
3472
3473 case L2CAP_CONN_REQ:
3474 err = l2cap_connect_req(conn, cmd, data);
3475 break;
3476
3477 case L2CAP_CONN_RSP:
3478 err = l2cap_connect_rsp(conn, cmd, data);
3479 break;
3480
3481 case L2CAP_CONF_REQ:
3482 err = l2cap_config_req(conn, cmd, cmd_len, data);
3483 break;
3484
3485 case L2CAP_CONF_RSP:
3486 err = l2cap_config_rsp(conn, cmd, data);
3487 break;
3488
3489 case L2CAP_DISCONN_REQ:
3490 err = l2cap_disconnect_req(conn, cmd, data);
3491 break;
3492
3493 case L2CAP_DISCONN_RSP:
3494 err = l2cap_disconnect_rsp(conn, cmd, data);
3495 break;
3496
3497 case L2CAP_ECHO_REQ:
3498 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3499 break;
3500
3501 case L2CAP_ECHO_RSP:
3502 break;
3503
3504 case L2CAP_INFO_REQ:
3505 err = l2cap_information_req(conn, cmd, data);
3506 break;
3507
3508 case L2CAP_INFO_RSP:
3509 err = l2cap_information_rsp(conn, cmd, data);
3510 break;
3511
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003512 case L2CAP_CREATE_CHAN_REQ:
3513 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3514 break;
3515
3516 case L2CAP_CREATE_CHAN_RSP:
3517 err = l2cap_create_channel_rsp(conn, cmd, data);
3518 break;
3519
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003520 case L2CAP_MOVE_CHAN_REQ:
3521 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3522 break;
3523
3524 case L2CAP_MOVE_CHAN_RSP:
3525 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3526 break;
3527
3528 case L2CAP_MOVE_CHAN_CFM:
3529 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3530 break;
3531
3532 case L2CAP_MOVE_CHAN_CFM_RSP:
3533 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3534 break;
3535
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003536 default:
3537 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3538 err = -EINVAL;
3539 break;
3540 }
3541
3542 return err;
3543}
3544
3545static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3546 struct l2cap_cmd_hdr *cmd, u8 *data)
3547{
3548 switch (cmd->code) {
3549 case L2CAP_COMMAND_REJ:
3550 return 0;
3551
3552 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003553 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003554
3555 case L2CAP_CONN_PARAM_UPDATE_RSP:
3556 return 0;
3557
3558 default:
3559 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3560 return -EINVAL;
3561 }
3562}
3563
3564static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3565 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566{
3567 u8 *data = skb->data;
3568 int len = skb->len;
3569 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003570 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571
3572 l2cap_raw_recv(conn, skb);
3573
3574 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003575 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3577 data += L2CAP_CMD_HDR_SIZE;
3578 len -= L2CAP_CMD_HDR_SIZE;
3579
Al Viro88219a02007-07-29 00:17:25 -07003580 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581
Al Viro88219a02007-07-29 00:17:25 -07003582 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 -07003583
Al Viro88219a02007-07-29 00:17:25 -07003584 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 BT_DBG("corrupted command");
3586 break;
3587 }
3588
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003589 if (conn->hcon->type == LE_LINK)
3590 err = l2cap_le_sig_cmd(conn, &cmd, data);
3591 else
3592 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593
3594 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003595 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003596
3597 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
3599 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003600 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3602 }
3603
Al Viro88219a02007-07-29 00:17:25 -07003604 data += cmd_len;
3605 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 }
3607
3608 kfree_skb(skb);
3609}
3610
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003611static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003612{
3613 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003614 int hdr_size;
3615
3616 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3617 hdr_size = L2CAP_EXT_HDR_SIZE;
3618 else
3619 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003620
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003621 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003622 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003623 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3624 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3625
3626 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003627 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003628 }
3629 return 0;
3630}
3631
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003632static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003633{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003634 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003635
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003636 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003637
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003638 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003639
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003640 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003641 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003642 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003643 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003644 }
3645
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003646 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003647 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003648
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003649 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003650
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003651 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003652 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003653 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003654 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003655 }
3656}
3657
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003658static 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 -03003659{
3660 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003661 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003662
3663 bt_cb(skb)->tx_seq = tx_seq;
3664 bt_cb(skb)->sar = sar;
3665
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003666 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003667
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003668 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003669
Szymon Janc039d9572011-11-16 09:32:19 +01003670 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003671 if (bt_cb(next_skb)->tx_seq == tx_seq)
3672 return -EINVAL;
3673
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003674 next_tx_seq_offset = __seq_offset(chan,
3675 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003676
3677 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003678 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003679 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003680 }
3681
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003682 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003683 next_skb = NULL;
3684 else
3685 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3686 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003687
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003688 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003689
3690 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003691}
3692
Mat Martineau84084a32011-07-22 14:54:00 -07003693static void append_skb_frag(struct sk_buff *skb,
3694 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003695{
Mat Martineau84084a32011-07-22 14:54:00 -07003696 /* skb->len reflects data in skb as well as all fragments
3697 * skb->data_len reflects only data in fragments
3698 */
3699 if (!skb_has_frag_list(skb))
3700 skb_shinfo(skb)->frag_list = new_frag;
3701
3702 new_frag->next = NULL;
3703
3704 (*last_frag)->next = new_frag;
3705 *last_frag = new_frag;
3706
3707 skb->len += new_frag->len;
3708 skb->data_len += new_frag->len;
3709 skb->truesize += new_frag->truesize;
3710}
3711
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003712static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003713{
3714 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003715
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003716 switch (__get_ctrl_sar(chan, control)) {
3717 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003718 if (chan->sdu)
3719 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003720
Mat Martineau84084a32011-07-22 14:54:00 -07003721 err = chan->ops->recv(chan->data, skb);
3722 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003723
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003724 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003725 if (chan->sdu)
3726 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003727
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003728 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003729 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003730
Mat Martineau84084a32011-07-22 14:54:00 -07003731 if (chan->sdu_len > chan->imtu) {
3732 err = -EMSGSIZE;
3733 break;
3734 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003735
Mat Martineau84084a32011-07-22 14:54:00 -07003736 if (skb->len >= chan->sdu_len)
3737 break;
3738
3739 chan->sdu = skb;
3740 chan->sdu_last_frag = skb;
3741
3742 skb = NULL;
3743 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003744 break;
3745
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003746 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003747 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003748 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003749
Mat Martineau84084a32011-07-22 14:54:00 -07003750 append_skb_frag(chan->sdu, skb,
3751 &chan->sdu_last_frag);
3752 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003753
Mat Martineau84084a32011-07-22 14:54:00 -07003754 if (chan->sdu->len >= chan->sdu_len)
3755 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003756
Mat Martineau84084a32011-07-22 14:54:00 -07003757 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003758 break;
3759
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003760 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003761 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003762 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003763
Mat Martineau84084a32011-07-22 14:54:00 -07003764 append_skb_frag(chan->sdu, skb,
3765 &chan->sdu_last_frag);
3766 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003767
Mat Martineau84084a32011-07-22 14:54:00 -07003768 if (chan->sdu->len != chan->sdu_len)
3769 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003770
Mat Martineau84084a32011-07-22 14:54:00 -07003771 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003772
Mat Martineau84084a32011-07-22 14:54:00 -07003773 if (!err) {
3774 /* Reassembly complete */
3775 chan->sdu = NULL;
3776 chan->sdu_last_frag = NULL;
3777 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003778 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003779 break;
3780 }
3781
Mat Martineau84084a32011-07-22 14:54:00 -07003782 if (err) {
3783 kfree_skb(skb);
3784 kfree_skb(chan->sdu);
3785 chan->sdu = NULL;
3786 chan->sdu_last_frag = NULL;
3787 chan->sdu_len = 0;
3788 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003789
Mat Martineau84084a32011-07-22 14:54:00 -07003790 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003791}
3792
Mat Martineau26f880d2011-07-07 09:39:01 -07003793static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003794{
Mat Martineau26f880d2011-07-07 09:39:01 -07003795 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003796
Mat Martineau26f880d2011-07-07 09:39:01 -07003797 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3798
Szymon Janc77f918b2012-01-11 10:59:48 +01003799 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003800}
3801
3802static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3803{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003804 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003805
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003806 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003807 goto done;
3808
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003809 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003810 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003811 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003812 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003813 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003814
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003815 __clear_retrans_timer(chan);
3816 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003817
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003818 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003819
3820done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003821 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3822 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003823
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003824 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003825}
3826
Mat Martineaue3281402011-07-07 09:39:02 -07003827void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003828{
Mat Martineaue3281402011-07-07 09:39:02 -07003829 if (chan->mode == L2CAP_MODE_ERTM) {
3830 if (busy)
3831 l2cap_ertm_enter_local_busy(chan);
3832 else
3833 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003834 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003835}
3836
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003837static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003838{
3839 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003840 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003841
Mat Martineaue3281402011-07-07 09:39:02 -07003842 while ((skb = skb_peek(&chan->srej_q)) &&
3843 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3844 int err;
3845
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003846 if (bt_cb(skb)->tx_seq != tx_seq)
3847 break;
3848
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003849 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003850 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003851 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003852
3853 if (err < 0) {
3854 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3855 break;
3856 }
3857
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003858 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3859 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003860 }
3861}
3862
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003863static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003864{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003865 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003866 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003867
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003868 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003869 if (l->tx_seq == tx_seq) {
3870 list_del(&l->list);
3871 kfree(l);
3872 return;
3873 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003874 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003875 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003876 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003877 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003878 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003879 }
3880}
3881
Szymon Jancaef89f22011-11-16 09:32:18 +01003882static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003883{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003884 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003885 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003886
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003887 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003888 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003889 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003890 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003891
3892 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003893 if (!new)
3894 return -ENOMEM;
3895
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003896 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003897
3898 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3899
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003900 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003901 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003902
3903 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003904
3905 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003906}
3907
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003908static 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 -03003909{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003910 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003911 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003912 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003913 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003914 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003915 int err = 0;
3916
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003917 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 -03003918 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003919
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003920 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003921 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003922 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003923 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003924 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003925 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003926 }
3927
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003928 chan->expected_ack_seq = req_seq;
3929 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003930
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003931 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003932
3933 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003934 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003935 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003936 goto drop;
3937 }
3938
Szymon Janc77f918b2012-01-11 10:59:48 +01003939 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3940 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3941 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003942 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003943 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003944
Mat Martineau02f1b642011-06-29 14:35:19 -07003945 if (tx_seq == chan->expected_tx_seq)
3946 goto expected;
3947
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003948 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003949 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003950
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003951 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003952 struct srej_list, list);
3953 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003954 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003955 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003956
3957 list_del(&first->list);
3958 kfree(first);
3959
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003960 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003961 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003962 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003963 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003964 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003965 }
3966 } else {
3967 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003968
3969 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003970 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003971 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003972
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003973 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003974 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003975 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003976 return 0;
3977 }
3978 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003979
3980 err = l2cap_send_srejframe(chan, tx_seq);
3981 if (err < 0) {
3982 l2cap_send_disconn_req(chan->conn, chan, -err);
3983 return err;
3984 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003985 }
3986 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003987 expected_tx_seq_offset = __seq_offset(chan,
3988 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003989
3990 /* duplicated tx_seq */
3991 if (tx_seq_offset < expected_tx_seq_offset)
3992 goto drop;
3993
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003994 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003995
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003996 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003997
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003998 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003999 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004000
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004001 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004002 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004003
Szymon Janc0ef3ef02012-01-11 10:59:46 +01004004 /* Set P-bit only if there are some I-frames to ack. */
4005 if (__clear_ack_timer(chan))
4006 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03004007
Szymon Jancaef89f22011-11-16 09:32:18 +01004008 err = l2cap_send_srejframe(chan, tx_seq);
4009 if (err < 0) {
4010 l2cap_send_disconn_req(chan->conn, chan, -err);
4011 return err;
4012 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004013 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004014 return 0;
4015
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004016expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004017 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004018
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004019 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03004020 bt_cb(skb)->tx_seq = tx_seq;
4021 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004022 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004023 return 0;
4024 }
4025
Mat Martineau84084a32011-07-22 14:54:00 -07004026 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004027 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4028
Mat Martineaue3281402011-07-07 09:39:02 -07004029 if (err < 0) {
4030 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4031 return err;
4032 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03004033
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004034 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004035 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004036 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03004037 }
4038
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03004039
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004040 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
4041 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004042 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03004043 else
4044 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03004045
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004046 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03004047
4048drop:
4049 kfree_skb(skb);
4050 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004051}
4052
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004053static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004054{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004055 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004056 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004057
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004058 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004059 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004060
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004061 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004062 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4063 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4064 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004065 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004066 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004067
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004068 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004069 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004070 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004071 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004072 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004073
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004074 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004075 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004076
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004077 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004078 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004079
4080 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004081 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004082 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004083 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004084
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004085 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4086 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004087 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004088 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004089 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004090 }
4091}
4092
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004093static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004094{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004095 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004096
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004097 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004098
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004099 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004100
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004101 chan->expected_ack_seq = tx_seq;
4102 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004103
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004104 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004105 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004106 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004107 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004108 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004109
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004110 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4111 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004112 }
4113}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004114static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004115{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004116 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004117
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004118 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004119
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004120 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004121
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004122 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004123 chan->expected_ack_seq = tx_seq;
4124 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004125
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004126 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004127 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004128
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004129 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004130
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004131 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004132 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004133 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004134 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004135 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004136 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004137 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004138 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004139 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004140 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004141 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004142 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004143 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004144 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004145 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004146 }
4147 }
4148}
4149
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004150static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004151{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004152 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004153
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004154 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004155
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004156 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004157 chan->expected_ack_seq = tx_seq;
4158 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004159
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004160 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004161 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004162
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004163 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004164 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004165 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004166 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004167 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004168 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004169
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004170 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004171 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004172 } else {
4173 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4174 l2cap_send_sframe(chan, rx_control);
4175 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004176}
4177
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004178static 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 -03004179{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004180 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004181
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004182 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004183 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004184 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004185 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004186 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004187 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004188 }
4189
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004190 switch (__get_ctrl_super(chan, rx_control)) {
4191 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004192 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004193 break;
4194
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004195 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004196 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004197 break;
4198
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004199 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004200 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004201 break;
4202
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004203 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004204 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004205 break;
4206 }
4207
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004208 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004209 return 0;
4210}
4211
Szymon Janccad8f1d02012-01-23 10:06:05 +01004212static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004213{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004214 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004215 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004216 int len, next_tx_seq_offset, req_seq_offset;
4217
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004218 control = __get_control(chan, skb->data);
4219 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004220 len = skb->len;
4221
4222 /*
4223 * We can just drop the corrupted I-frame here.
4224 * Receiver will miss it and start proper recovery
4225 * procedures and ask retransmission.
4226 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004227 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004228 goto drop;
4229
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004230 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004231 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004232
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004233 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004234 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004235
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004236 if (len > chan->mps) {
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
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004241 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004242
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004243 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4244
4245 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4246 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004247
4248 /* check for invalid req-seq */
4249 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004250 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004251 goto drop;
4252 }
4253
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004254 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004255 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004256 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004257 goto drop;
4258 }
4259
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004260 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004261 } else {
4262 if (len != 0) {
4263 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004264 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004265 goto drop;
4266 }
4267
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004268 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004269 }
4270
4271 return 0;
4272
4273drop:
4274 kfree_skb(skb);
4275 return 0;
4276}
4277
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4279{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004280 struct l2cap_chan *chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004281 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004282 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004283 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004285 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004286 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287 BT_DBG("unknown cid 0x%4.4x", cid);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004288 /* Drop packet and return */
Dan Carpenter33790132012-02-28 09:52:46 +03004289 kfree_skb(skb);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004290 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 }
4292
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004293 l2cap_chan_lock(chan);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004294
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004295 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004297 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 goto drop;
4299
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004300 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004301 case L2CAP_MODE_BASIC:
4302 /* If socket recv buffers overflows we drop data here
4303 * which is *bad* because L2CAP has to be reliable.
4304 * But we don't have any other choice. L2CAP doesn't
4305 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004307 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004308 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004310 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004311 goto done;
4312 break;
4313
4314 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004315 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004316
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004317 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004318
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004319 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004320 control = __get_control(chan, skb->data);
4321 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004322 len = skb->len;
4323
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004324 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004325 goto drop;
4326
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004327 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004328 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004329
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004330 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004331 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004332
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004333 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004334 goto drop;
4335
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004336 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004337
Mat Martineau84084a32011-07-22 14:54:00 -07004338 if (chan->expected_tx_seq != tx_seq) {
4339 /* Frame(s) missing - must discard partial SDU */
4340 kfree_skb(chan->sdu);
4341 chan->sdu = NULL;
4342 chan->sdu_last_frag = NULL;
4343 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004344
Mat Martineau84084a32011-07-22 14:54:00 -07004345 /* TODO: Notify userland of missing data */
4346 }
4347
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004348 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004349
4350 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4351 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004352
4353 goto done;
4354
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004355 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004356 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004357 break;
4358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359
4360drop:
4361 kfree_skb(skb);
4362
4363done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004364 l2cap_chan_unlock(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +02004365
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366 return 0;
4367}
4368
Al Viro8e036fc2007-07-29 00:16:36 -07004369static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004371 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004373 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4374 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 goto drop;
4376
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004377 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004379 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 goto drop;
4381
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004382 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 goto drop;
4384
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004385 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004386 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387
4388drop:
4389 kfree_skb(skb);
4390
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 return 0;
4392}
4393
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004394static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4395{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004396 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004397
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004398 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4399 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004400 goto drop;
4401
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004402 BT_DBG("chan %p, len %d", chan, skb->len);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004403
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004404 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004405 goto drop;
4406
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004407 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004408 goto drop;
4409
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004410 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004411 return 0;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004412
4413drop:
4414 kfree_skb(skb);
4415
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004416 return 0;
4417}
4418
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4420{
4421 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004422 u16 cid, len;
4423 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424
4425 skb_pull(skb, L2CAP_HDR_SIZE);
4426 cid = __le16_to_cpu(lh->cid);
4427 len = __le16_to_cpu(lh->len);
4428
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004429 if (len != skb->len) {
4430 kfree_skb(skb);
4431 return;
4432 }
4433
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4435
4436 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004437 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004438 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 l2cap_sig_channel(conn, skb);
4440 break;
4441
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004442 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004443 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 skb_pull(skb, 2);
4445 l2cap_conless_channel(conn, psm, skb);
4446 break;
4447
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004448 case L2CAP_CID_LE_DATA:
4449 l2cap_att_channel(conn, cid, skb);
4450 break;
4451
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004452 case L2CAP_CID_SMP:
4453 if (smp_sig_channel(conn, skb))
4454 l2cap_conn_del(conn->hcon, EACCES);
4455 break;
4456
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457 default:
4458 l2cap_data_channel(conn, cid, skb);
4459 break;
4460 }
4461}
4462
4463/* ---- L2CAP interface with lower layer (HCI) ---- */
4464
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004465int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466{
4467 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004468 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4471
4472 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004473 read_lock(&chan_list_lock);
4474 list_for_each_entry(c, &chan_list, global_l) {
4475 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004476
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004477 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 continue;
4479
4480 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004481 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004482 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004483 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004485 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4486 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004487 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004488 lm2 |= HCI_LM_MASTER;
4489 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004491 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492
4493 return exact ? lm1 : lm2;
4494}
4495
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004496int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497{
Marcel Holtmann01394182006-07-03 10:02:46 +02004498 struct l2cap_conn *conn;
4499
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4501
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 conn = l2cap_conn_add(hcon, status);
4504 if (conn)
4505 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004506 } else
Joe Perchese1750722011-06-29 18:18:29 -07004507 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508
4509 return 0;
4510}
4511
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004512int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004513{
4514 struct l2cap_conn *conn = hcon->l2cap_data;
4515
4516 BT_DBG("hcon %p", hcon);
4517
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004518 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004519 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004520 return conn->disc_reason;
4521}
4522
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004523int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524{
4525 BT_DBG("hcon %p reason %d", hcon, reason);
4526
Joe Perchese1750722011-06-29 18:18:29 -07004527 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528 return 0;
4529}
4530
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004531static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004532{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004533 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004534 return;
4535
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004536 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004537 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004538 __clear_chan_timer(chan);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004539 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004540 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004541 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004542 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004543 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004544 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004545 }
4546}
4547
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004548int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004550 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004551 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552
Marcel Holtmann01394182006-07-03 10:02:46 +02004553 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004555
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556 BT_DBG("conn %p", conn);
4557
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004558 if (hcon->type == LE_LINK) {
4559 smp_distribute_keys(conn, 0);
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02004560 cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004561 }
4562
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004563 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004565 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004566 l2cap_chan_lock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004568 BT_DBG("chan->scid %d", chan->scid);
4569
4570 if (chan->scid == L2CAP_CID_LE_DATA) {
4571 if (!status && encrypt) {
4572 chan->sec_level = hcon->sec_level;
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02004573 l2cap_chan_ready(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004574 }
4575
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004576 l2cap_chan_unlock(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004577 continue;
4578 }
4579
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004580 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004581 l2cap_chan_unlock(chan);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004582 continue;
4583 }
4584
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004585 if (!status && (chan->state == BT_CONNECTED ||
4586 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004587 l2cap_check_encryption(chan, encrypt);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004588 l2cap_chan_unlock(chan);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004589 continue;
4590 }
4591
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004592 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004593 if (!status) {
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +02004594 l2cap_send_conn_req(chan);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004595 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004596 __clear_chan_timer(chan);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004597 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004598 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004599 } else if (chan->state == BT_CONNECT2) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004600 struct sock *sk = chan->sk;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004601 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004602 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004603
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004604 lock_sock(sk);
4605
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004606 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004607 if (bt_sk(sk)->defer_setup) {
4608 struct sock *parent = bt_sk(sk)->parent;
4609 res = L2CAP_CR_PEND;
4610 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004611 if (parent)
4612 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004613 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004614 __l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004615 res = L2CAP_CR_SUCCESS;
4616 stat = L2CAP_CS_NO_INFO;
4617 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004618 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004619 __l2cap_state_change(chan, BT_DISCONN);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004620 __set_chan_timer(chan, 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
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004625 release_sock(sk);
4626
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004627 rsp.scid = cpu_to_le16(chan->dcid);
4628 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004629 rsp.result = cpu_to_le16(res);
4630 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004631 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4632 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 }
4634
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004635 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004636 }
4637
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004638 mutex_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004639
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 return 0;
4641}
4642
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004643int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644{
4645 struct l2cap_conn *conn = hcon->l2cap_data;
4646
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004647 if (!conn)
4648 conn = l2cap_conn_add(hcon, 0);
4649
4650 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 goto drop;
4652
4653 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4654
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004655 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004657 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004658 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 int len;
4660
4661 if (conn->rx_len) {
4662 BT_ERR("Unexpected start frame (len %d)", skb->len);
4663 kfree_skb(conn->rx_skb);
4664 conn->rx_skb = NULL;
4665 conn->rx_len = 0;
4666 l2cap_conn_unreliable(conn, ECOMM);
4667 }
4668
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004669 /* Start fragment always begin with Basic L2CAP header */
4670 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 BT_ERR("Frame is too short (len %d)", skb->len);
4672 l2cap_conn_unreliable(conn, ECOMM);
4673 goto drop;
4674 }
4675
4676 hdr = (struct l2cap_hdr *) skb->data;
4677 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004678 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679
4680 if (len == skb->len) {
4681 /* Complete frame received */
4682 l2cap_recv_frame(conn, skb);
4683 return 0;
4684 }
4685
4686 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4687
4688 if (skb->len > len) {
4689 BT_ERR("Frame is too long (len %d, expected len %d)",
4690 skb->len, len);
4691 l2cap_conn_unreliable(conn, ECOMM);
4692 goto drop;
4693 }
4694
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004695 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004696
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004697 if (chan && chan->sk) {
4698 struct sock *sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004699 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004700
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004701 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004702 BT_ERR("Frame exceeding recv MTU (len %d, "
4703 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004704 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004705 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004706 l2cap_conn_unreliable(conn, ECOMM);
4707 goto drop;
4708 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004709 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004710 }
4711
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004713 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4714 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715 goto drop;
4716
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004717 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004718 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 conn->rx_len = len - skb->len;
4720 } else {
4721 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4722
4723 if (!conn->rx_len) {
4724 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4725 l2cap_conn_unreliable(conn, ECOMM);
4726 goto drop;
4727 }
4728
4729 if (skb->len > conn->rx_len) {
4730 BT_ERR("Fragment is too long (len %d, expected %d)",
4731 skb->len, conn->rx_len);
4732 kfree_skb(conn->rx_skb);
4733 conn->rx_skb = NULL;
4734 conn->rx_len = 0;
4735 l2cap_conn_unreliable(conn, ECOMM);
4736 goto drop;
4737 }
4738
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004739 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004740 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 conn->rx_len -= skb->len;
4742
4743 if (!conn->rx_len) {
4744 /* Complete frame received */
4745 l2cap_recv_frame(conn, conn->rx_skb);
4746 conn->rx_skb = NULL;
4747 }
4748 }
4749
4750drop:
4751 kfree_skb(skb);
4752 return 0;
4753}
4754
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004755static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004757 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004759 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004761 list_for_each_entry(c, &chan_list, global_l) {
4762 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004764 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 +01004765 batostr(&bt_sk(sk)->src),
4766 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004767 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004768 c->scid, c->dcid, c->imtu, c->omtu,
4769 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004770 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004772 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004773
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004774 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775}
4776
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004777static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4778{
4779 return single_open(file, l2cap_debugfs_show, inode->i_private);
4780}
4781
4782static const struct file_operations l2cap_debugfs_fops = {
4783 .open = l2cap_debugfs_open,
4784 .read = seq_read,
4785 .llseek = seq_lseek,
4786 .release = single_release,
4787};
4788
4789static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004791int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792{
4793 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004794
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004795 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 if (err < 0)
4797 return err;
4798
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004799 if (bt_debugfs) {
4800 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4801 bt_debugfs, NULL, &l2cap_debugfs_fops);
4802 if (!l2cap_debugfs)
4803 BT_ERR("Failed to create L2CAP debug file");
4804 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807}
4808
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004809void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004811 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004812 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813}
4814
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004815module_param(disable_ertm, bool, 0644);
4816MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");