blob: df3be692f2cfc0eff9d772836d4a93753bc30e0b [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
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200703 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200704 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
705
706 l2cap_send_cmd(conn, conn->info_ident,
707 L2CAP_INFO_REQ, sizeof(req), &req);
708 }
709}
710
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300711static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
712{
713 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300714 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300715 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
716
717 switch (mode) {
718 case L2CAP_MODE_ERTM:
719 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
720 case L2CAP_MODE_STREAMING:
721 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
722 default:
723 return 0x00;
724 }
725}
726
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300727static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300728{
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200729 struct sock *sk = chan->sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300730 struct l2cap_disconn_req req;
731
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300732 if (!conn)
733 return;
734
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300735 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300736 __clear_retrans_timer(chan);
737 __clear_monitor_timer(chan);
738 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300739 }
740
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300741 req.dcid = cpu_to_le16(chan->dcid);
742 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300743 l2cap_send_cmd(conn, l2cap_get_ident(conn),
744 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300745
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200746 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200747 __l2cap_state_change(chan, BT_DISCONN);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200748 __l2cap_chan_set_err(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200749 release_sock(sk);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300750}
751
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200753static void l2cap_conn_start(struct l2cap_conn *conn)
754{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200755 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200756
757 BT_DBG("conn %p", conn);
758
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200759 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200760
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200761 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300762 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300763
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200764 l2cap_chan_lock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200765
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300766 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200767 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200768 continue;
769 }
770
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300771 if (chan->state == BT_CONNECT) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200772 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300773 !__l2cap_no_conn_pending(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200774 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300775 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200776 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300777
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300778 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
779 && test_bit(CONF_STATE2_DEVICE,
780 &chan->conf_state)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300781 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200782 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300783 continue;
784 }
785
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200786 l2cap_send_conn_req(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300787
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300788 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200789 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300790 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300791 rsp.scid = cpu_to_le16(chan->dcid);
792 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200793
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200794 if (l2cap_chan_check_security(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200795 lock_sock(sk);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100796 if (bt_sk(sk)->defer_setup) {
797 struct sock *parent = bt_sk(sk)->parent;
798 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
799 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000800 if (parent)
801 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100802
803 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200804 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100805 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
806 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
807 }
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200808 release_sock(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200809 } else {
810 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
811 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
812 }
813
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300814 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
815 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300816
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300817 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300818 rsp.result != L2CAP_CR_SUCCESS) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200819 l2cap_chan_unlock(chan);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300820 continue;
821 }
822
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300823 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300824 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300825 l2cap_build_conf_req(chan, buf), buf);
826 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200827 }
828
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200829 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200830 }
831
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200832 mutex_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200833}
834
Ville Tervob62f3282011-02-10 22:38:50 -0300835/* Find socket with cid and source bdaddr.
836 * Returns closest match, locked.
837 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300838static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300839{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300840 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300841
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300842 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300843
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300844 list_for_each_entry(c, &chan_list, global_l) {
845 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300846
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300847 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300848 continue;
849
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300850 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300851 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300852 if (!bacmp(&bt_sk(sk)->src, src)) {
853 read_unlock(&chan_list_lock);
854 return c;
855 }
Ville Tervob62f3282011-02-10 22:38:50 -0300856
857 /* Closest match */
858 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300859 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300860 }
861 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300862
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300863 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300864
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300865 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300866}
867
868static void l2cap_le_conn_ready(struct l2cap_conn *conn)
869{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300870 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300871 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300872
873 BT_DBG("");
874
875 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300876 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300877 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300878 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300879 return;
880
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300881 parent = pchan->sk;
882
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300883 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300884
Ville Tervob62f3282011-02-10 22:38:50 -0300885 /* Check for backlog size */
886 if (sk_acceptq_is_full(parent)) {
887 BT_DBG("backlog full %d", parent->sk_ack_backlog);
888 goto clean;
889 }
890
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300891 chan = pchan->ops->new_connection(pchan->data);
892 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300893 goto clean;
894
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300895 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300896
Ville Tervob62f3282011-02-10 22:38:50 -0300897 hci_conn_hold(conn->hcon);
898
Ville Tervob62f3282011-02-10 22:38:50 -0300899 bacpy(&bt_sk(sk)->src, conn->src);
900 bacpy(&bt_sk(sk)->dst, conn->dst);
901
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300902 bt_accept_enqueue(parent, sk);
903
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200904 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300905
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300906 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300907
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200908 __l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300909 parent->sk_data_ready(parent, 0);
910
Ville Tervob62f3282011-02-10 22:38:50 -0300911clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300912 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300913}
914
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200915static void l2cap_chan_ready(struct l2cap_chan *chan)
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300916{
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200917 struct sock *sk = chan->sk;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200918 struct sock *parent;
919
920 lock_sock(sk);
921
922 parent = bt_sk(sk)->parent;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300923
924 BT_DBG("sk %p, parent %p", sk, parent);
925
926 chan->conf_state = 0;
927 __clear_chan_timer(chan);
928
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200929 __l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300930 sk->sk_state_change(sk);
931
932 if (parent)
933 parent->sk_data_ready(parent, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200934
935 release_sock(sk);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300936}
937
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200938static void l2cap_conn_ready(struct l2cap_conn *conn)
939{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300940 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200941
942 BT_DBG("conn %p", conn);
943
Ville Tervob62f3282011-02-10 22:38:50 -0300944 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
945 l2cap_le_conn_ready(conn);
946
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300947 if (conn->hcon->out && conn->hcon->type == LE_LINK)
948 smp_conn_security(conn, conn->hcon->pending_sec_level);
949
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200950 mutex_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200951
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200952 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300953
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200954 l2cap_chan_lock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200955
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300956 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300957 if (smp_conn_security(conn, chan->sec_level))
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200958 l2cap_chan_ready(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300959
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300960 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200961 struct sock *sk = chan->sk;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300962 __clear_chan_timer(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200963 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200964 __l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200965 sk->sk_state_change(sk);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200966 release_sock(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300967
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300968 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300969 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200970
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200971 l2cap_chan_unlock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200972 }
973
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200974 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200975}
976
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200977/* Notify sockets that we cannot guaranty reliability anymore */
978static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
979{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300980 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200981
982 BT_DBG("conn %p", conn);
983
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200984 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200985
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200986 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300987 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200988 __l2cap_chan_set_err(chan, err);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200989 }
990
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200991 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200992}
993
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200994static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200995{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200996 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200997 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200998
Marcel Holtmann984947d2009-02-06 23:35:19 +0100999 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01001000 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01001001
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001002 l2cap_conn_start(conn);
1003}
1004
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001005static void l2cap_conn_del(struct hci_conn *hcon, int err)
1006{
1007 struct l2cap_conn *conn = hcon->l2cap_data;
1008 struct l2cap_chan *chan, *l;
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001009
1010 if (!conn)
1011 return;
1012
1013 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1014
1015 kfree_skb(conn->rx_skb);
1016
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001017 mutex_lock(&conn->chan_lock);
1018
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001019 /* Kill channels */
1020 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001021 l2cap_chan_lock(chan);
1022
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001023 l2cap_chan_del(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001024
1025 l2cap_chan_unlock(chan);
1026
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001027 chan->ops->close(chan->data);
1028 }
1029
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001030 mutex_unlock(&conn->chan_lock);
1031
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001032 hci_chan_del(conn->hchan);
1033
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001034 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim127074b2012-01-30 18:26:29 -02001035 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001036
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001037 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim127074b2012-01-30 18:26:29 -02001038 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001039 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001040 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001041
1042 hcon->l2cap_data = NULL;
1043 kfree(conn);
1044}
1045
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001046static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001047{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001048 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1049 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001050
1051 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1052}
1053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1055{
Marcel Holtmann01394182006-07-03 10:02:46 +02001056 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001057 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058
Marcel Holtmann01394182006-07-03 10:02:46 +02001059 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return conn;
1061
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001062 hchan = hci_chan_create(hcon);
1063 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001066 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1067 if (!conn) {
1068 hci_chan_del(hchan);
1069 return NULL;
1070 }
1071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 hcon->l2cap_data = conn;
1073 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001074 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001076 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001077
Ville Tervoacd7d372011-02-10 22:38:49 -03001078 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1079 conn->mtu = hcon->hdev->le_mtu;
1080 else
1081 conn->mtu = hcon->hdev->acl_mtu;
1082
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 conn->src = &hcon->hdev->bdaddr;
1084 conn->dst = &hcon->dst;
1085
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001086 conn->feat_mask = 0;
1087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 spin_lock_init(&conn->lock);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001089 mutex_init(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001090
1091 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001093 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001094 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001095 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001096 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001097
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001098 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001099
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 return conn;
1101}
1102
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105/* Find socket with psm and source bdaddr.
1106 * Returns closest match.
1107 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001108static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001110 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001112 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001113
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001114 list_for_each_entry(c, &chan_list, global_l) {
1115 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001116
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001117 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 continue;
1119
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001120 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001122 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001123 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001124 return c;
1125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
1127 /* Closest match */
1128 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001129 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 }
1131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001133 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001134
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001135 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136}
1137
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001138int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001140 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 struct l2cap_conn *conn;
1143 struct hci_conn *hcon;
1144 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001145 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001146 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001148 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001149 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001151 hdev = hci_get_route(dst, src);
1152 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 return -EHOSTUNREACH;
1154
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001155 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001157 l2cap_chan_lock(chan);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001158
1159 /* PSM must be odd and lsb of upper byte must be 0 */
1160 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1161 chan->chan_type != L2CAP_CHAN_RAW) {
1162 err = -EINVAL;
1163 goto done;
1164 }
1165
1166 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1167 err = -EINVAL;
1168 goto done;
1169 }
1170
1171 switch (chan->mode) {
1172 case L2CAP_MODE_BASIC:
1173 break;
1174 case L2CAP_MODE_ERTM:
1175 case L2CAP_MODE_STREAMING:
1176 if (!disable_ertm)
1177 break;
1178 /* fall through */
1179 default:
1180 err = -ENOTSUPP;
1181 goto done;
1182 }
1183
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001184 lock_sock(sk);
1185
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001186 switch (sk->sk_state) {
1187 case BT_CONNECT:
1188 case BT_CONNECT2:
1189 case BT_CONFIG:
1190 /* Already connecting */
1191 err = 0;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001192 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001193 goto done;
1194
1195 case BT_CONNECTED:
1196 /* Already connected */
1197 err = -EISCONN;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001198 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001199 goto done;
1200
1201 case BT_OPEN:
1202 case BT_BOUND:
1203 /* Can connect */
1204 break;
1205
1206 default:
1207 err = -EBADFD;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001208 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001209 goto done;
1210 }
1211
1212 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001213 bacpy(&bt_sk(sk)->dst, dst);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001214
1215 release_sock(sk);
1216
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001217 chan->psm = psm;
1218 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001220 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001221
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001222 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001223 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001224 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001225 else
1226 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001227 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001228
Ville Tervo30e76272011-02-22 16:10:53 -03001229 if (IS_ERR(hcon)) {
1230 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
1234 conn = l2cap_conn_add(hcon, 0);
1235 if (!conn) {
1236 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001237 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 goto done;
1239 }
1240
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 /* Update source addr of the socket */
1242 bacpy(src, conn->src);
1243
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001244 l2cap_chan_unlock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001245 l2cap_chan_add(conn, chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001246 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001247
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001248 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001249 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250
1251 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001252 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001253 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001254 if (l2cap_chan_check_security(chan))
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001255 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001256 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001257 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 }
1259
Ville Tervo30e76272011-02-22 16:10:53 -03001260 err = 0;
1261
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001263 l2cap_chan_unlock(chan);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001264 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 hci_dev_put(hdev);
1266 return err;
1267}
1268
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001269int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001270{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001271 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001272 DECLARE_WAITQUEUE(wait, current);
1273 int err = 0;
1274 int timeo = HZ/5;
1275
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001276 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001277 set_current_state(TASK_INTERRUPTIBLE);
1278 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001279 if (!timeo)
1280 timeo = HZ/5;
1281
1282 if (signal_pending(current)) {
1283 err = sock_intr_errno(timeo);
1284 break;
1285 }
1286
1287 release_sock(sk);
1288 timeo = schedule_timeout(timeo);
1289 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001290 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001291
1292 err = sock_error(sk);
1293 if (err)
1294 break;
1295 }
1296 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001297 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001298 return err;
1299}
1300
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001301static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001302{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001303 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1304 monitor_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001305
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001306 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001307
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001308 l2cap_chan_lock(chan);
1309
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001310 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001311 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001312 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001313 return;
1314 }
1315
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001316 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001317 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001318
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001319 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001320 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001321}
1322
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001323static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001324{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001325 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1326 retrans_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001327
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001328 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001329
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001330 l2cap_chan_lock(chan);
1331
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001332 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001333 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001334
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001335 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001336
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001337 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001338
1339 l2cap_chan_unlock(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001340}
1341
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001342static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001343{
1344 struct sk_buff *skb;
1345
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001346 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001347 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001348 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001349 break;
1350
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001351 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001352 kfree_skb(skb);
1353
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001354 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001355 }
1356
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001357 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001358 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001359}
1360
Szymon Janc67c9e842011-07-28 16:24:33 +02001361static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001362{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001363 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001364 u32 control;
1365 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001366
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001367 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001368 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001369 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001370 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001371
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001372 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001373 fcs = crc16(0, (u8 *)skb->data,
1374 skb->len - L2CAP_FCS_SIZE);
1375 put_unaligned_le16(fcs,
1376 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001377 }
1378
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001379 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001380
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001381 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001382 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001383}
1384
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001385static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001386{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001387 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001388 u16 fcs;
1389 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001390
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001391 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001392 if (!skb)
1393 return;
1394
Szymon Jancd1726b62011-11-16 09:32:20 +01001395 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001396 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001397 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001398
Szymon Jancd1726b62011-11-16 09:32:20 +01001399 skb = skb_queue_next(&chan->tx_q, skb);
1400 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001401
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001402 if (chan->remote_max_tx &&
1403 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001404 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001405 return;
1406 }
1407
1408 tx_skb = skb_clone(skb, GFP_ATOMIC);
1409 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001410
1411 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001412 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001413
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001414 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001415 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001416
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001417 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001418 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001419
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001420 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001421
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001422 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001423 fcs = crc16(0, (u8 *)tx_skb->data,
1424 tx_skb->len - L2CAP_FCS_SIZE);
1425 put_unaligned_le16(fcs,
1426 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001427 }
1428
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001429 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001430}
1431
Szymon Janc67c9e842011-07-28 16:24:33 +02001432static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001433{
1434 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001435 u16 fcs;
1436 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001437 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001438
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001439 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001440 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001441
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001442 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001443
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001444 if (chan->remote_max_tx &&
1445 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001446 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001447 break;
1448 }
1449
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001450 tx_skb = skb_clone(skb, GFP_ATOMIC);
1451
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001452 bt_cb(skb)->retries++;
1453
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001454 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001455 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001456
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001457 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001458 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001459
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001460 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001461 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001462
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001463 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001464
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001465 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001466 fcs = crc16(0, (u8 *)skb->data,
1467 tx_skb->len - L2CAP_FCS_SIZE);
1468 put_unaligned_le16(fcs, skb->data +
1469 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001470 }
1471
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001472 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001473
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001474 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001475
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001476 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001477
1478 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001479
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001480 if (bt_cb(skb)->retries == 1) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001481 chan->unacked_frames++;
Szymon Janc930fa4a2012-02-07 15:43:02 +01001482
1483 if (!nsent++)
1484 __clear_ack_timer(chan);
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001485 }
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301486
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001487 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001488
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001489 if (skb_queue_is_last(&chan->tx_q, skb))
1490 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001491 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001492 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001493 }
1494
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001495 return nsent;
1496}
1497
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001498static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001499{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001500 int ret;
1501
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001502 if (!skb_queue_empty(&chan->tx_q))
1503 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001504
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001505 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001506 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001507 return ret;
1508}
1509
Szymon Jancb17e73b2012-01-11 10:59:47 +01001510static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001511{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001512 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001513
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001514 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001515
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001516 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001517 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001518 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001519 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001520 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001521 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001522
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001523 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001524 return;
1525
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001526 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001527 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001528}
1529
Szymon Jancb17e73b2012-01-11 10:59:47 +01001530static void l2cap_send_ack(struct l2cap_chan *chan)
1531{
1532 __clear_ack_timer(chan);
1533 __l2cap_send_ack(chan);
1534}
1535
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001536static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001537{
1538 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001539 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001540
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001541 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001542 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001543
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001544 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001545 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001546
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001547 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001548}
1549
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001550static 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 -07001551{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001552 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001553 struct sk_buff **frag;
1554 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001556 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001557 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
1559 sent += count;
1560 len -= count;
1561
1562 /* Continuation fragments (no L2CAP header) */
1563 frag = &skb_shinfo(skb)->frag_list;
1564 while (len) {
1565 count = min_t(unsigned int, conn->mtu, len);
1566
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001567 *frag = chan->ops->alloc_skb(chan, count,
1568 msg->msg_flags & MSG_DONTWAIT, &err);
1569
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001571 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001572 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1573 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001575 (*frag)->priority = skb->priority;
1576
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 sent += count;
1578 len -= count;
1579
1580 frag = &(*frag)->next;
1581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
1583 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001584}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001586static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1587 struct msghdr *msg, size_t len,
1588 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001589{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001590 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001591 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001592 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001593 struct l2cap_hdr *lh;
1594
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001595 BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001596
1597 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001598
1599 skb = chan->ops->alloc_skb(chan, count + hlen,
1600 msg->msg_flags & MSG_DONTWAIT, &err);
1601
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001602 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001603 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001604
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001605 skb->priority = priority;
1606
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001607 /* Create L2CAP header */
1608 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001609 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001610 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001611 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001612
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001613 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001614 if (unlikely(err < 0)) {
1615 kfree_skb(skb);
1616 return ERR_PTR(err);
1617 }
1618 return skb;
1619}
1620
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001621static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1622 struct msghdr *msg, size_t len,
1623 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001624{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001625 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001626 struct sk_buff *skb;
1627 int err, count, hlen = L2CAP_HDR_SIZE;
1628 struct l2cap_hdr *lh;
1629
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001630 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001631
1632 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001633
1634 skb = chan->ops->alloc_skb(chan, count + hlen,
1635 msg->msg_flags & MSG_DONTWAIT, &err);
1636
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001637 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001638 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001639
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001640 skb->priority = priority;
1641
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001642 /* Create L2CAP header */
1643 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001644 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001645 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1646
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001647 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001648 if (unlikely(err < 0)) {
1649 kfree_skb(skb);
1650 return ERR_PTR(err);
1651 }
1652 return skb;
1653}
1654
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001655static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1656 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001657 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001658{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001659 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001660 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001661 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001662 struct l2cap_hdr *lh;
1663
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001664 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001665
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001666 if (!conn)
1667 return ERR_PTR(-ENOTCONN);
1668
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001669 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1670 hlen = L2CAP_EXT_HDR_SIZE;
1671 else
1672 hlen = L2CAP_ENH_HDR_SIZE;
1673
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001674 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001675 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001676
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001677 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001678 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001679
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001680 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001681
1682 skb = chan->ops->alloc_skb(chan, count + hlen,
1683 msg->msg_flags & MSG_DONTWAIT, &err);
1684
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001685 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001686 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001687
1688 /* Create L2CAP header */
1689 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001690 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001691 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001692
1693 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1694
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001695 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001696 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001697
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001698 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001699 if (unlikely(err < 0)) {
1700 kfree_skb(skb);
1701 return ERR_PTR(err);
1702 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001703
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001704 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001705 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001706
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001707 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001708 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709}
1710
Szymon Janc67c9e842011-07-28 16:24:33 +02001711static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001712{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001713 struct sk_buff *skb;
1714 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001715 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001716 size_t size = 0;
1717
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001718 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001719 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001720 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001721 if (IS_ERR(skb))
1722 return PTR_ERR(skb);
1723
1724 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001725 len -= chan->remote_mps;
1726 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001727
1728 while (len > 0) {
1729 size_t buflen;
1730
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001731 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001732 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001733 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001734 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001735 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001736 buflen = len;
1737 }
1738
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001739 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001740 if (IS_ERR(skb)) {
1741 skb_queue_purge(&sar_queue);
1742 return PTR_ERR(skb);
1743 }
1744
1745 __skb_queue_tail(&sar_queue, skb);
1746 len -= buflen;
1747 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001748 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001749 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1750 if (chan->tx_send_head == NULL)
1751 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001752
1753 return size;
1754}
1755
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001756int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1757 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001758{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001759 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001760 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001761 int err;
1762
1763 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001764 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001765 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001766 if (IS_ERR(skb))
1767 return PTR_ERR(skb);
1768
1769 l2cap_do_send(chan, skb);
1770 return len;
1771 }
1772
1773 switch (chan->mode) {
1774 case L2CAP_MODE_BASIC:
1775 /* Check outgoing MTU */
1776 if (len > chan->omtu)
1777 return -EMSGSIZE;
1778
1779 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001780 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001781 if (IS_ERR(skb))
1782 return PTR_ERR(skb);
1783
1784 l2cap_do_send(chan, skb);
1785 err = len;
1786 break;
1787
1788 case L2CAP_MODE_ERTM:
1789 case L2CAP_MODE_STREAMING:
1790 /* Entire SDU fits into one PDU */
1791 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001792 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001793 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1794 0);
1795 if (IS_ERR(skb))
1796 return PTR_ERR(skb);
1797
1798 __skb_queue_tail(&chan->tx_q, skb);
1799
1800 if (chan->tx_send_head == NULL)
1801 chan->tx_send_head = skb;
1802
1803 } else {
1804 /* Segment SDU into multiples PDUs */
1805 err = l2cap_sar_segment_sdu(chan, msg, len);
1806 if (err < 0)
1807 return err;
1808 }
1809
1810 if (chan->mode == L2CAP_MODE_STREAMING) {
1811 l2cap_streaming_send(chan);
1812 err = len;
1813 break;
1814 }
1815
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001816 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1817 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001818 err = len;
1819 break;
1820 }
1821
1822 err = l2cap_ertm_send(chan);
1823 if (err >= 0)
1824 err = len;
1825
1826 break;
1827
1828 default:
1829 BT_DBG("bad state %1.1x", chan->mode);
1830 err = -EBADFD;
1831 }
1832
1833 return err;
1834}
1835
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836/* Copy frame to all raw sockets on that connection */
1837static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1838{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001840 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841
1842 BT_DBG("conn %p", conn);
1843
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001844 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001845
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001846 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001847 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001848 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849 continue;
1850
1851 /* Don't send frame to the socket it came from */
1852 if (skb->sk == sk)
1853 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001854 nskb = skb_clone(skb, GFP_ATOMIC);
1855 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 continue;
1857
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001858 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 kfree_skb(nskb);
1860 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001861
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001862 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863}
1864
1865/* ---- L2CAP signalling commands ---- */
1866static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1867 u8 code, u8 ident, u16 dlen, void *data)
1868{
1869 struct sk_buff *skb, **frag;
1870 struct l2cap_cmd_hdr *cmd;
1871 struct l2cap_hdr *lh;
1872 int len, count;
1873
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001874 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1875 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
1877 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1878 count = min_t(unsigned int, conn->mtu, len);
1879
1880 skb = bt_skb_alloc(count, GFP_ATOMIC);
1881 if (!skb)
1882 return NULL;
1883
1884 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001885 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001886
1887 if (conn->hcon->type == LE_LINK)
1888 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1889 else
1890 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
1892 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1893 cmd->code = code;
1894 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001895 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
1897 if (dlen) {
1898 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1899 memcpy(skb_put(skb, count), data, count);
1900 data += count;
1901 }
1902
1903 len -= skb->len;
1904
1905 /* Continuation fragments (no L2CAP header) */
1906 frag = &skb_shinfo(skb)->frag_list;
1907 while (len) {
1908 count = min_t(unsigned int, conn->mtu, len);
1909
1910 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1911 if (!*frag)
1912 goto fail;
1913
1914 memcpy(skb_put(*frag, count), data, count);
1915
1916 len -= count;
1917 data += count;
1918
1919 frag = &(*frag)->next;
1920 }
1921
1922 return skb;
1923
1924fail:
1925 kfree_skb(skb);
1926 return NULL;
1927}
1928
1929static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1930{
1931 struct l2cap_conf_opt *opt = *ptr;
1932 int len;
1933
1934 len = L2CAP_CONF_OPT_SIZE + opt->len;
1935 *ptr += len;
1936
1937 *type = opt->type;
1938 *olen = opt->len;
1939
1940 switch (opt->len) {
1941 case 1:
1942 *val = *((u8 *) opt->val);
1943 break;
1944
1945 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001946 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 break;
1948
1949 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001950 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 break;
1952
1953 default:
1954 *val = (unsigned long) opt->val;
1955 break;
1956 }
1957
1958 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1959 return len;
1960}
1961
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1963{
1964 struct l2cap_conf_opt *opt = *ptr;
1965
1966 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1967
1968 opt->type = type;
1969 opt->len = len;
1970
1971 switch (len) {
1972 case 1:
1973 *((u8 *) opt->val) = val;
1974 break;
1975
1976 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001977 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 break;
1979
1980 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001981 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 break;
1983
1984 default:
1985 memcpy(opt->val, (void *) val, len);
1986 break;
1987 }
1988
1989 *ptr += L2CAP_CONF_OPT_SIZE + len;
1990}
1991
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001992static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1993{
1994 struct l2cap_conf_efs efs;
1995
Szymon Janc1ec918c2011-11-16 09:32:21 +01001996 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001997 case L2CAP_MODE_ERTM:
1998 efs.id = chan->local_id;
1999 efs.stype = chan->local_stype;
2000 efs.msdu = cpu_to_le16(chan->local_msdu);
2001 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2002 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
2003 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
2004 break;
2005
2006 case L2CAP_MODE_STREAMING:
2007 efs.id = 1;
2008 efs.stype = L2CAP_SERV_BESTEFFORT;
2009 efs.msdu = cpu_to_le16(chan->local_msdu);
2010 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2011 efs.acc_lat = 0;
2012 efs.flush_to = 0;
2013 break;
2014
2015 default:
2016 return;
2017 }
2018
2019 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
2020 (unsigned long) &efs);
2021}
2022
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002023static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002024{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002025 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2026 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002027
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02002028 BT_DBG("chan %p", chan);
2029
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002030 l2cap_chan_lock(chan);
2031
Szymon Jancb17e73b2012-01-11 10:59:47 +01002032 __l2cap_send_ack(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002033
2034 l2cap_chan_unlock(chan);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002035
2036 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002037}
2038
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002039static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002040{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002041 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002042 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002043 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002044 chan->num_acked = 0;
2045 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002046
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002047 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2048 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2049 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002050
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002051 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002052
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002053 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002054}
2055
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002056static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2057{
2058 switch (mode) {
2059 case L2CAP_MODE_STREAMING:
2060 case L2CAP_MODE_ERTM:
2061 if (l2cap_mode_supported(mode, remote_feat_mask))
2062 return mode;
2063 /* fall through */
2064 default:
2065 return L2CAP_MODE_BASIC;
2066 }
2067}
2068
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002069static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2070{
2071 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2072}
2073
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002074static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2075{
2076 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2077}
2078
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002079static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2080{
2081 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002082 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002083 /* use extended control field */
2084 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002085 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2086 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002087 chan->tx_win = min_t(u16, chan->tx_win,
2088 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002089 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2090 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002091}
2092
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002093static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002096 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002098 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002100 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002102 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002103 goto done;
2104
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002105 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002106 case L2CAP_MODE_STREAMING:
2107 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002108 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002109 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002110
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002111 if (__l2cap_efs_supported(chan))
2112 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2113
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002114 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002115 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002116 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002117 break;
2118 }
2119
2120done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002121 if (chan->imtu != L2CAP_DEFAULT_MTU)
2122 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002123
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002124 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002125 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002126 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2127 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002128 break;
2129
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002130 rfc.mode = L2CAP_MODE_BASIC;
2131 rfc.txwin_size = 0;
2132 rfc.max_transmit = 0;
2133 rfc.retrans_timeout = 0;
2134 rfc.monitor_timeout = 0;
2135 rfc.max_pdu_size = 0;
2136
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002137 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2138 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002139 break;
2140
2141 case L2CAP_MODE_ERTM:
2142 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002143 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002144 rfc.retrans_timeout = 0;
2145 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002146
2147 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2148 L2CAP_EXT_HDR_SIZE -
2149 L2CAP_SDULEN_SIZE -
2150 L2CAP_FCS_SIZE);
2151 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002152
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002153 l2cap_txwin_setup(chan);
2154
2155 rfc.txwin_size = min_t(u16, chan->tx_win,
2156 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002157
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002158 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2159 (unsigned long) &rfc);
2160
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002161 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2162 l2cap_add_opt_efs(&ptr, chan);
2163
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002164 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002165 break;
2166
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002167 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002168 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002169 chan->fcs = L2CAP_FCS_NONE;
2170 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002171 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002172
2173 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2174 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2175 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002176 break;
2177
2178 case L2CAP_MODE_STREAMING:
2179 rfc.mode = L2CAP_MODE_STREAMING;
2180 rfc.txwin_size = 0;
2181 rfc.max_transmit = 0;
2182 rfc.retrans_timeout = 0;
2183 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002184
2185 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2186 L2CAP_EXT_HDR_SIZE -
2187 L2CAP_SDULEN_SIZE -
2188 L2CAP_FCS_SIZE);
2189 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002190
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002191 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2192 (unsigned long) &rfc);
2193
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002194 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2195 l2cap_add_opt_efs(&ptr, chan);
2196
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002197 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002198 break;
2199
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002200 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002201 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002202 chan->fcs = L2CAP_FCS_NONE;
2203 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002204 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002205 break;
2206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002208 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002209 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
2211 return ptr - data;
2212}
2213
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002214static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002216 struct l2cap_conf_rsp *rsp = data;
2217 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002218 void *req = chan->conf_req;
2219 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002220 int type, hint, olen;
2221 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002222 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002223 struct l2cap_conf_efs efs;
2224 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002225 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002226 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002227 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002229 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002230
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002231 while (len >= L2CAP_CONF_OPT_SIZE) {
2232 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002234 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002235 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002236
2237 switch (type) {
2238 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002239 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002240 break;
2241
2242 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002243 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002244 break;
2245
2246 case L2CAP_CONF_QOS:
2247 break;
2248
Marcel Holtmann6464f352007-10-20 13:39:51 +02002249 case L2CAP_CONF_RFC:
2250 if (olen == sizeof(rfc))
2251 memcpy(&rfc, (void *) val, olen);
2252 break;
2253
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002254 case L2CAP_CONF_FCS:
2255 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002256 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002257 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002258
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002259 case L2CAP_CONF_EFS:
2260 remote_efs = 1;
2261 if (olen == sizeof(efs))
2262 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002263 break;
2264
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002265 case L2CAP_CONF_EWS:
2266 if (!enable_hs)
2267 return -ECONNREFUSED;
2268
2269 set_bit(FLAG_EXT_CTRL, &chan->flags);
2270 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002271 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002272 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002273 break;
2274
2275 default:
2276 if (hint)
2277 break;
2278
2279 result = L2CAP_CONF_UNKNOWN;
2280 *((u8 *) ptr++) = type;
2281 break;
2282 }
2283 }
2284
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002285 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002286 goto done;
2287
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002288 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002289 case L2CAP_MODE_STREAMING:
2290 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002291 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002292 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002293 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002294 break;
2295 }
2296
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002297 if (remote_efs) {
2298 if (__l2cap_efs_supported(chan))
2299 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2300 else
2301 return -ECONNREFUSED;
2302 }
2303
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002304 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002305 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002306
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002307 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002308 }
2309
2310done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002311 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002312 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002313 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002314
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002315 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002316 return -ECONNREFUSED;
2317
2318 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2319 sizeof(rfc), (unsigned long) &rfc);
2320 }
2321
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002322 if (result == L2CAP_CONF_SUCCESS) {
2323 /* Configure output options and let the other side know
2324 * which ones we don't like. */
2325
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002326 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2327 result = L2CAP_CONF_UNACCEPT;
2328 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002329 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002330 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002331 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002332 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002333
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002334 if (remote_efs) {
2335 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2336 efs.stype != L2CAP_SERV_NOTRAFIC &&
2337 efs.stype != chan->local_stype) {
2338
2339 result = L2CAP_CONF_UNACCEPT;
2340
2341 if (chan->num_conf_req >= 1)
2342 return -ECONNREFUSED;
2343
2344 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002345 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002346 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002347 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002348 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002349 result = L2CAP_CONF_PENDING;
2350 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002351 }
2352 }
2353
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002354 switch (rfc.mode) {
2355 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002356 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002357 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002358 break;
2359
2360 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002361 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2362 chan->remote_tx_win = rfc.txwin_size;
2363 else
2364 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2365
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002366 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002367
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002368 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2369 chan->conn->mtu -
2370 L2CAP_EXT_HDR_SIZE -
2371 L2CAP_SDULEN_SIZE -
2372 L2CAP_FCS_SIZE);
2373 rfc.max_pdu_size = cpu_to_le16(size);
2374 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002375
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002376 rfc.retrans_timeout =
2377 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2378 rfc.monitor_timeout =
2379 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002380
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002381 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002382
2383 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2384 sizeof(rfc), (unsigned long) &rfc);
2385
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002386 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2387 chan->remote_id = efs.id;
2388 chan->remote_stype = efs.stype;
2389 chan->remote_msdu = le16_to_cpu(efs.msdu);
2390 chan->remote_flush_to =
2391 le32_to_cpu(efs.flush_to);
2392 chan->remote_acc_lat =
2393 le32_to_cpu(efs.acc_lat);
2394 chan->remote_sdu_itime =
2395 le32_to_cpu(efs.sdu_itime);
2396 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2397 sizeof(efs), (unsigned long) &efs);
2398 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002399 break;
2400
2401 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002402 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2403 chan->conn->mtu -
2404 L2CAP_EXT_HDR_SIZE -
2405 L2CAP_SDULEN_SIZE -
2406 L2CAP_FCS_SIZE);
2407 rfc.max_pdu_size = cpu_to_le16(size);
2408 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002409
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002410 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002411
2412 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2413 sizeof(rfc), (unsigned long) &rfc);
2414
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002415 break;
2416
2417 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002418 result = L2CAP_CONF_UNACCEPT;
2419
2420 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002421 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002422 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002423
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002424 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002425 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002426 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002427 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002428 rsp->result = cpu_to_le16(result);
2429 rsp->flags = cpu_to_le16(0x0000);
2430
2431 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432}
2433
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002434static 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 -03002435{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002436 struct l2cap_conf_req *req = data;
2437 void *ptr = req->data;
2438 int type, olen;
2439 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002440 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002441 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002442
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002443 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002444
2445 while (len >= L2CAP_CONF_OPT_SIZE) {
2446 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2447
2448 switch (type) {
2449 case L2CAP_CONF_MTU:
2450 if (val < L2CAP_DEFAULT_MIN_MTU) {
2451 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002452 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002453 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002454 chan->imtu = val;
2455 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002456 break;
2457
2458 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002459 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002460 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002461 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002462 break;
2463
2464 case L2CAP_CONF_RFC:
2465 if (olen == sizeof(rfc))
2466 memcpy(&rfc, (void *)val, olen);
2467
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002468 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002469 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002470 return -ECONNREFUSED;
2471
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002472 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002473
2474 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2475 sizeof(rfc), (unsigned long) &rfc);
2476 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002477
2478 case L2CAP_CONF_EWS:
2479 chan->tx_win = min_t(u16, val,
2480 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002481 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2482 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002483 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002484
2485 case L2CAP_CONF_EFS:
2486 if (olen == sizeof(efs))
2487 memcpy(&efs, (void *)val, olen);
2488
2489 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2490 efs.stype != L2CAP_SERV_NOTRAFIC &&
2491 efs.stype != chan->local_stype)
2492 return -ECONNREFUSED;
2493
2494 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2495 sizeof(efs), (unsigned long) &efs);
2496 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002497 }
2498 }
2499
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002500 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002501 return -ECONNREFUSED;
2502
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002503 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002504
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002505 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002506 switch (rfc.mode) {
2507 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002508 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2509 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2510 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002511
2512 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2513 chan->local_msdu = le16_to_cpu(efs.msdu);
2514 chan->local_sdu_itime =
2515 le32_to_cpu(efs.sdu_itime);
2516 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2517 chan->local_flush_to =
2518 le32_to_cpu(efs.flush_to);
2519 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002520 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002521
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002522 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002523 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002524 }
2525 }
2526
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002527 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002528 req->flags = cpu_to_le16(0x0000);
2529
2530 return ptr - data;
2531}
2532
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002533static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534{
2535 struct l2cap_conf_rsp *rsp = data;
2536 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002538 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002540 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002541 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002542 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543
2544 return ptr - data;
2545}
2546
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002547void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002548{
2549 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002550 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002551 u8 buf[128];
2552
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002553 rsp.scid = cpu_to_le16(chan->dcid);
2554 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002555 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2556 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2557 l2cap_send_cmd(conn, chan->ident,
2558 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2559
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002560 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002561 return;
2562
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002563 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2564 l2cap_build_conf_req(chan, buf), buf);
2565 chan->num_conf_req++;
2566}
2567
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002568static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002569{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002570 int type, olen;
2571 unsigned long val;
2572 struct l2cap_conf_rfc rfc;
2573
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002574 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002575
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002576 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002577 return;
2578
2579 while (len >= L2CAP_CONF_OPT_SIZE) {
2580 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2581
2582 switch (type) {
2583 case L2CAP_CONF_RFC:
2584 if (olen == sizeof(rfc))
2585 memcpy(&rfc, (void *)val, olen);
2586 goto done;
2587 }
2588 }
2589
Mat Martineau36e999a2011-12-08 17:23:21 -08002590 /* Use sane default values in case a misbehaving remote device
2591 * did not send an RFC option.
2592 */
2593 rfc.mode = chan->mode;
2594 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2595 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2596 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2597
2598 BT_ERR("Expected RFC option was not found, using defaults");
2599
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002600done:
2601 switch (rfc.mode) {
2602 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002603 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2604 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2605 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002606 break;
2607 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002608 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002609 }
2610}
2611
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002612static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2613{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002614 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002615
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002616 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002617 return 0;
2618
2619 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2620 cmd->ident == conn->info_ident) {
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02002621 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002622
2623 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002624 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002625
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002626 l2cap_conn_start(conn);
2627 }
2628
2629 return 0;
2630}
2631
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2633{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2635 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002636 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002637 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002638 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639
2640 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002641 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642
2643 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2644
2645 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002646 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2647 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 result = L2CAP_CR_BAD_PSM;
2649 goto sendresp;
2650 }
2651
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002652 parent = pchan->sk;
2653
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002654 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002655 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002656
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002657 /* Check if the ACL is secure enough (if not SDP) */
2658 if (psm != cpu_to_le16(0x0001) &&
2659 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002660 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002661 result = L2CAP_CR_SEC_BLOCK;
2662 goto response;
2663 }
2664
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 result = L2CAP_CR_NO_MEM;
2666
2667 /* Check for backlog size */
2668 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002669 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 goto response;
2671 }
2672
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002673 chan = pchan->ops->new_connection(pchan->data);
2674 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 goto response;
2676
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002677 sk = chan->sk;
2678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002680 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002682 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 goto response;
2684 }
2685
2686 hci_conn_hold(conn->hcon);
2687
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 bacpy(&bt_sk(sk)->src, conn->src);
2689 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002690 chan->psm = psm;
2691 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002693 bt_accept_enqueue(parent, sk);
2694
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002695 __l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002696
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002697 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002699 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002701 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
Marcel Holtmann984947d2009-02-06 23:35:19 +01002703 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002704 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002705 if (bt_sk(sk)->defer_setup) {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002706 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002707 result = L2CAP_CR_PEND;
2708 status = L2CAP_CS_AUTHOR_PEND;
2709 parent->sk_data_ready(parent, 0);
2710 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002711 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002712 result = L2CAP_CR_SUCCESS;
2713 status = L2CAP_CS_NO_INFO;
2714 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002715 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002716 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002717 result = L2CAP_CR_PEND;
2718 status = L2CAP_CS_AUTHEN_PEND;
2719 }
2720 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002721 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002722 result = L2CAP_CR_PEND;
2723 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 }
2725
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002727 release_sock(parent);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002728 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729
2730sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002731 rsp.scid = cpu_to_le16(scid);
2732 rsp.dcid = cpu_to_le16(dcid);
2733 rsp.result = cpu_to_le16(result);
2734 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002736
2737 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2738 struct l2cap_info_req info;
2739 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2740
2741 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2742 conn->info_ident = l2cap_get_ident(conn);
2743
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02002744 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002745 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2746
2747 l2cap_send_cmd(conn, conn->info_ident,
2748 L2CAP_INFO_REQ, sizeof(info), &info);
2749 }
2750
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002751 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002752 result == L2CAP_CR_SUCCESS) {
2753 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002754 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002755 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002756 l2cap_build_conf_req(chan, buf), buf);
2757 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002758 }
2759
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 return 0;
2761}
2762
2763static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2764{
2765 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2766 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002767 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 u8 req[128];
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002769 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770
2771 scid = __le16_to_cpu(rsp->scid);
2772 dcid = __le16_to_cpu(rsp->dcid);
2773 result = __le16_to_cpu(rsp->result);
2774 status = __le16_to_cpu(rsp->status);
2775
Andrei Emeltchenko1b009c92012-02-21 12:54:54 +02002776 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
2777 dcid, scid, result, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002779 mutex_lock(&conn->chan_lock);
2780
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 if (scid) {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002782 chan = __l2cap_get_chan_by_scid(conn, scid);
2783 if (!chan) {
2784 err = -EFAULT;
2785 goto unlock;
2786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 } else {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002788 chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
2789 if (!chan) {
2790 err = -EFAULT;
2791 goto unlock;
2792 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 }
2794
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002795 err = 0;
2796
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002797 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002798
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 switch (result) {
2800 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002801 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002802 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002803 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002804 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002805
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002806 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002807 break;
2808
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002810 l2cap_build_conf_req(chan, req), req);
2811 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 break;
2813
2814 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002815 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 break;
2817
2818 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002819 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 break;
2821 }
2822
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002823 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002824
2825unlock:
2826 mutex_unlock(&conn->chan_lock);
2827
2828 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829}
2830
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002831static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002832{
2833 /* FCS is enabled only in ERTM or streaming mode, if one or both
2834 * sides request it.
2835 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002836 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002837 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002838 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002839 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002840}
2841
Al Viro88219a02007-07-29 00:17:25 -07002842static 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 -07002843{
2844 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2845 u16 dcid, flags;
2846 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002847 struct l2cap_chan *chan;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002848 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849
2850 dcid = __le16_to_cpu(req->dcid);
2851 flags = __le16_to_cpu(req->flags);
2852
2853 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2854
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002855 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002856 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 return -ENOENT;
2858
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002859 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002860
David S. Miller033b1142011-07-21 13:38:42 -07002861 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002862 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002863
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002864 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2865 rej.scid = cpu_to_le16(chan->scid);
2866 rej.dcid = cpu_to_le16(chan->dcid);
2867
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002868 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2869 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002870 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002871 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002872
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002873 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002874 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002875 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002876 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002877 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002878 L2CAP_CONF_REJECT, flags), rsp);
2879 goto unlock;
2880 }
2881
2882 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002883 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2884 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885
2886 if (flags & 0x0001) {
2887 /* Incomplete config. Send empty response. */
2888 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002889 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002890 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 goto unlock;
2892 }
2893
2894 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002895 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002896 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002897 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002899 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002901 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002902 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002903
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002904 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002905 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002906
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002907 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002908 goto unlock;
2909
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002910 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002911 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002912
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002913 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002914
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002915 chan->next_tx_seq = 0;
2916 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002917 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002918 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002919 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002920
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02002921 l2cap_chan_ready(chan);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002922 goto unlock;
2923 }
2924
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002925 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002926 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002928 l2cap_build_conf_req(chan, buf), buf);
2929 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 }
2931
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002932 /* Got Conf Rsp PENDING from remote side and asume we sent
2933 Conf Rsp PENDING in the code above */
2934 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2935 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2936
2937 /* check compatibility */
2938
2939 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2940 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2941
2942 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002943 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002944 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2945 }
2946
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947unlock:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002948 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 return 0;
2950}
2951
2952static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2953{
2954 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2955 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002956 struct l2cap_chan *chan;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002957 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958
2959 scid = __le16_to_cpu(rsp->scid);
2960 flags = __le16_to_cpu(rsp->flags);
2961 result = __le16_to_cpu(rsp->result);
2962
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002963 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2964 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002966 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002967 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 return 0;
2969
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002970 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002971
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 switch (result) {
2973 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002974 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002975 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 break;
2977
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002978 case L2CAP_CONF_PENDING:
2979 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2980
2981 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2982 char buf[64];
2983
2984 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2985 buf, &result);
2986 if (len < 0) {
2987 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2988 goto done;
2989 }
2990
2991 /* check compatibility */
2992
2993 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2994 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2995
2996 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002997 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002998 L2CAP_CONF_SUCCESS, 0x0000), buf);
2999 }
3000 goto done;
3001
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003003 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003004 char req[64];
3005
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003006 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003007 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003008 goto done;
3009 }
3010
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003011 /* throw out any old stored conf requests */
3012 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03003013 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
3014 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003015 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003016 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003017 goto done;
3018 }
3019
3020 l2cap_send_cmd(conn, l2cap_get_ident(conn),
3021 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003022 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003023 if (result != L2CAP_CONF_SUCCESS)
3024 goto done;
3025 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 }
3027
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09003028 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003029 l2cap_chan_set_err(chan, ECONNRESET);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +02003030
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01003031 __set_chan_timer(chan,
3032 msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT));
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003033 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 goto done;
3035 }
3036
3037 if (flags & 0x01)
3038 goto done;
3039
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003040 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003042 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003043 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003044
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003045 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003046 chan->next_tx_seq = 0;
3047 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003048 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003049 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003050 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003051
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02003052 l2cap_chan_ready(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 }
3054
3055done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003056 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 return 0;
3058}
3059
3060static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3061{
3062 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3063 struct l2cap_disconn_rsp rsp;
3064 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003065 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 struct sock *sk;
3067
3068 scid = __le16_to_cpu(req->scid);
3069 dcid = __le16_to_cpu(req->dcid);
3070
3071 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3072
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003073 mutex_lock(&conn->chan_lock);
3074
3075 chan = __l2cap_get_chan_by_scid(conn, dcid);
3076 if (!chan) {
3077 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003081 l2cap_chan_lock(chan);
3082
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003083 sk = chan->sk;
3084
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003085 rsp.dcid = cpu_to_le16(chan->scid);
3086 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3088
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003089 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 sk->sk_shutdown = SHUTDOWN_MASK;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003091 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003093 l2cap_chan_del(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003094
3095 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003097 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003098
3099 mutex_unlock(&conn->chan_lock);
3100
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 return 0;
3102}
3103
3104static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3105{
3106 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3107 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003108 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110 scid = __le16_to_cpu(rsp->scid);
3111 dcid = __le16_to_cpu(rsp->dcid);
3112
3113 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3114
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003115 mutex_lock(&conn->chan_lock);
3116
3117 chan = __l2cap_get_chan_by_scid(conn, scid);
3118 if (!chan) {
3119 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003123 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003124
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003125 l2cap_chan_del(chan, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003126
3127 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003129 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003130
3131 mutex_unlock(&conn->chan_lock);
3132
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 return 0;
3134}
3135
3136static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3137{
3138 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 u16 type;
3140
3141 type = __le16_to_cpu(req->type);
3142
3143 BT_DBG("type 0x%4.4x", type);
3144
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003145 if (type == L2CAP_IT_FEAT_MASK) {
3146 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003147 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003148 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3149 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3150 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003151 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003152 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3153 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003154 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003155 feat_mask |= L2CAP_FEAT_EXT_FLOW
3156 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003157
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003158 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003159 l2cap_send_cmd(conn, cmd->ident,
3160 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003161 } else if (type == L2CAP_IT_FIXED_CHAN) {
3162 u8 buf[12];
3163 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003164
3165 if (enable_hs)
3166 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3167 else
3168 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3169
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003170 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3171 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003172 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003173 l2cap_send_cmd(conn, cmd->ident,
3174 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003175 } else {
3176 struct l2cap_info_rsp rsp;
3177 rsp.type = cpu_to_le16(type);
3178 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3179 l2cap_send_cmd(conn, cmd->ident,
3180 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
3183 return 0;
3184}
3185
3186static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3187{
3188 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3189 u16 type, result;
3190
3191 type = __le16_to_cpu(rsp->type);
3192 result = __le16_to_cpu(rsp->result);
3193
3194 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3195
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003196 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3197 if (cmd->ident != conn->info_ident ||
3198 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3199 return 0;
3200
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02003201 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003202
Ville Tervoadb08ed2010-08-04 09:43:33 +03003203 if (result != L2CAP_IR_SUCCESS) {
3204 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3205 conn->info_ident = 0;
3206
3207 l2cap_conn_start(conn);
3208
3209 return 0;
3210 }
3211
Marcel Holtmann984947d2009-02-06 23:35:19 +01003212 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003213 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003214
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003215 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003216 struct l2cap_info_req req;
3217 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3218
3219 conn->info_ident = l2cap_get_ident(conn);
3220
3221 l2cap_send_cmd(conn, conn->info_ident,
3222 L2CAP_INFO_REQ, sizeof(req), &req);
3223 } else {
3224 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3225 conn->info_ident = 0;
3226
3227 l2cap_conn_start(conn);
3228 }
3229 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003230 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003231 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003232
3233 l2cap_conn_start(conn);
3234 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003235
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 return 0;
3237}
3238
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003239static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3240 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3241 void *data)
3242{
3243 struct l2cap_create_chan_req *req = data;
3244 struct l2cap_create_chan_rsp rsp;
3245 u16 psm, scid;
3246
3247 if (cmd_len != sizeof(*req))
3248 return -EPROTO;
3249
3250 if (!enable_hs)
3251 return -EINVAL;
3252
3253 psm = le16_to_cpu(req->psm);
3254 scid = le16_to_cpu(req->scid);
3255
3256 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3257
3258 /* Placeholder: Always reject */
3259 rsp.dcid = 0;
3260 rsp.scid = cpu_to_le16(scid);
3261 rsp.result = L2CAP_CR_NO_MEM;
3262 rsp.status = L2CAP_CS_NO_INFO;
3263
3264 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3265 sizeof(rsp), &rsp);
3266
3267 return 0;
3268}
3269
3270static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3271 struct l2cap_cmd_hdr *cmd, void *data)
3272{
3273 BT_DBG("conn %p", conn);
3274
3275 return l2cap_connect_rsp(conn, cmd, data);
3276}
3277
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003278static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3279 u16 icid, u16 result)
3280{
3281 struct l2cap_move_chan_rsp rsp;
3282
3283 BT_DBG("icid %d, result %d", icid, result);
3284
3285 rsp.icid = cpu_to_le16(icid);
3286 rsp.result = cpu_to_le16(result);
3287
3288 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3289}
3290
3291static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3292 struct l2cap_chan *chan, u16 icid, u16 result)
3293{
3294 struct l2cap_move_chan_cfm cfm;
3295 u8 ident;
3296
3297 BT_DBG("icid %d, result %d", icid, result);
3298
3299 ident = l2cap_get_ident(conn);
3300 if (chan)
3301 chan->ident = ident;
3302
3303 cfm.icid = cpu_to_le16(icid);
3304 cfm.result = cpu_to_le16(result);
3305
3306 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3307}
3308
3309static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3310 u16 icid)
3311{
3312 struct l2cap_move_chan_cfm_rsp rsp;
3313
3314 BT_DBG("icid %d", icid);
3315
3316 rsp.icid = cpu_to_le16(icid);
3317 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3318}
3319
3320static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3321 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3322{
3323 struct l2cap_move_chan_req *req = data;
3324 u16 icid = 0;
3325 u16 result = L2CAP_MR_NOT_ALLOWED;
3326
3327 if (cmd_len != sizeof(*req))
3328 return -EPROTO;
3329
3330 icid = le16_to_cpu(req->icid);
3331
3332 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3333
3334 if (!enable_hs)
3335 return -EINVAL;
3336
3337 /* Placeholder: Always refuse */
3338 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3339
3340 return 0;
3341}
3342
3343static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3344 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3345{
3346 struct l2cap_move_chan_rsp *rsp = data;
3347 u16 icid, result;
3348
3349 if (cmd_len != sizeof(*rsp))
3350 return -EPROTO;
3351
3352 icid = le16_to_cpu(rsp->icid);
3353 result = le16_to_cpu(rsp->result);
3354
3355 BT_DBG("icid %d, result %d", icid, result);
3356
3357 /* Placeholder: Always unconfirmed */
3358 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3359
3360 return 0;
3361}
3362
3363static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3364 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3365{
3366 struct l2cap_move_chan_cfm *cfm = data;
3367 u16 icid, result;
3368
3369 if (cmd_len != sizeof(*cfm))
3370 return -EPROTO;
3371
3372 icid = le16_to_cpu(cfm->icid);
3373 result = le16_to_cpu(cfm->result);
3374
3375 BT_DBG("icid %d, result %d", icid, result);
3376
3377 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3378
3379 return 0;
3380}
3381
3382static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3383 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3384{
3385 struct l2cap_move_chan_cfm_rsp *rsp = data;
3386 u16 icid;
3387
3388 if (cmd_len != sizeof(*rsp))
3389 return -EPROTO;
3390
3391 icid = le16_to_cpu(rsp->icid);
3392
3393 BT_DBG("icid %d", icid);
3394
3395 return 0;
3396}
3397
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003398static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003399 u16 to_multiplier)
3400{
3401 u16 max_latency;
3402
3403 if (min > max || min < 6 || max > 3200)
3404 return -EINVAL;
3405
3406 if (to_multiplier < 10 || to_multiplier > 3200)
3407 return -EINVAL;
3408
3409 if (max >= to_multiplier * 8)
3410 return -EINVAL;
3411
3412 max_latency = (to_multiplier * 8 / max) - 1;
3413 if (latency > 499 || latency > max_latency)
3414 return -EINVAL;
3415
3416 return 0;
3417}
3418
3419static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3420 struct l2cap_cmd_hdr *cmd, u8 *data)
3421{
3422 struct hci_conn *hcon = conn->hcon;
3423 struct l2cap_conn_param_update_req *req;
3424 struct l2cap_conn_param_update_rsp rsp;
3425 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003426 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003427
3428 if (!(hcon->link_mode & HCI_LM_MASTER))
3429 return -EINVAL;
3430
3431 cmd_len = __le16_to_cpu(cmd->len);
3432 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3433 return -EPROTO;
3434
3435 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003436 min = __le16_to_cpu(req->min);
3437 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003438 latency = __le16_to_cpu(req->latency);
3439 to_multiplier = __le16_to_cpu(req->to_multiplier);
3440
3441 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3442 min, max, latency, to_multiplier);
3443
3444 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003445
3446 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3447 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003448 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3449 else
3450 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3451
3452 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3453 sizeof(rsp), &rsp);
3454
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003455 if (!err)
3456 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3457
Claudio Takahaside731152011-02-11 19:28:55 -02003458 return 0;
3459}
3460
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003461static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3462 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3463{
3464 int err = 0;
3465
3466 switch (cmd->code) {
3467 case L2CAP_COMMAND_REJ:
3468 l2cap_command_rej(conn, cmd, data);
3469 break;
3470
3471 case L2CAP_CONN_REQ:
3472 err = l2cap_connect_req(conn, cmd, data);
3473 break;
3474
3475 case L2CAP_CONN_RSP:
3476 err = l2cap_connect_rsp(conn, cmd, data);
3477 break;
3478
3479 case L2CAP_CONF_REQ:
3480 err = l2cap_config_req(conn, cmd, cmd_len, data);
3481 break;
3482
3483 case L2CAP_CONF_RSP:
3484 err = l2cap_config_rsp(conn, cmd, data);
3485 break;
3486
3487 case L2CAP_DISCONN_REQ:
3488 err = l2cap_disconnect_req(conn, cmd, data);
3489 break;
3490
3491 case L2CAP_DISCONN_RSP:
3492 err = l2cap_disconnect_rsp(conn, cmd, data);
3493 break;
3494
3495 case L2CAP_ECHO_REQ:
3496 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3497 break;
3498
3499 case L2CAP_ECHO_RSP:
3500 break;
3501
3502 case L2CAP_INFO_REQ:
3503 err = l2cap_information_req(conn, cmd, data);
3504 break;
3505
3506 case L2CAP_INFO_RSP:
3507 err = l2cap_information_rsp(conn, cmd, data);
3508 break;
3509
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003510 case L2CAP_CREATE_CHAN_REQ:
3511 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3512 break;
3513
3514 case L2CAP_CREATE_CHAN_RSP:
3515 err = l2cap_create_channel_rsp(conn, cmd, data);
3516 break;
3517
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003518 case L2CAP_MOVE_CHAN_REQ:
3519 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3520 break;
3521
3522 case L2CAP_MOVE_CHAN_RSP:
3523 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3524 break;
3525
3526 case L2CAP_MOVE_CHAN_CFM:
3527 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3528 break;
3529
3530 case L2CAP_MOVE_CHAN_CFM_RSP:
3531 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3532 break;
3533
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003534 default:
3535 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3536 err = -EINVAL;
3537 break;
3538 }
3539
3540 return err;
3541}
3542
3543static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3544 struct l2cap_cmd_hdr *cmd, u8 *data)
3545{
3546 switch (cmd->code) {
3547 case L2CAP_COMMAND_REJ:
3548 return 0;
3549
3550 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003551 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003552
3553 case L2CAP_CONN_PARAM_UPDATE_RSP:
3554 return 0;
3555
3556 default:
3557 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3558 return -EINVAL;
3559 }
3560}
3561
3562static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3563 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564{
3565 u8 *data = skb->data;
3566 int len = skb->len;
3567 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003568 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569
3570 l2cap_raw_recv(conn, skb);
3571
3572 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003573 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3575 data += L2CAP_CMD_HDR_SIZE;
3576 len -= L2CAP_CMD_HDR_SIZE;
3577
Al Viro88219a02007-07-29 00:17:25 -07003578 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579
Al Viro88219a02007-07-29 00:17:25 -07003580 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 -07003581
Al Viro88219a02007-07-29 00:17:25 -07003582 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 BT_DBG("corrupted command");
3584 break;
3585 }
3586
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003587 if (conn->hcon->type == LE_LINK)
3588 err = l2cap_le_sig_cmd(conn, &cmd, data);
3589 else
3590 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591
3592 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003593 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003594
3595 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003598 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3600 }
3601
Al Viro88219a02007-07-29 00:17:25 -07003602 data += cmd_len;
3603 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 }
3605
3606 kfree_skb(skb);
3607}
3608
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003609static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003610{
3611 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003612 int hdr_size;
3613
3614 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3615 hdr_size = L2CAP_EXT_HDR_SIZE;
3616 else
3617 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003618
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003619 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003620 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003621 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3622 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3623
3624 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003625 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003626 }
3627 return 0;
3628}
3629
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003630static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003631{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003632 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003633
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003634 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003635
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003636 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003637
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003638 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003639 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003640 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003641 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003642 }
3643
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003644 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003645 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003646
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003647 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003648
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003649 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003650 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003651 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003652 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003653 }
3654}
3655
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003656static 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 -03003657{
3658 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003659 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003660
3661 bt_cb(skb)->tx_seq = tx_seq;
3662 bt_cb(skb)->sar = sar;
3663
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003664 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003665
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003666 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003667
Szymon Janc039d9572011-11-16 09:32:19 +01003668 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003669 if (bt_cb(next_skb)->tx_seq == tx_seq)
3670 return -EINVAL;
3671
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003672 next_tx_seq_offset = __seq_offset(chan,
3673 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003674
3675 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003676 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003677 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003678 }
3679
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003680 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003681 next_skb = NULL;
3682 else
3683 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3684 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003685
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003686 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003687
3688 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003689}
3690
Mat Martineau84084a32011-07-22 14:54:00 -07003691static void append_skb_frag(struct sk_buff *skb,
3692 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003693{
Mat Martineau84084a32011-07-22 14:54:00 -07003694 /* skb->len reflects data in skb as well as all fragments
3695 * skb->data_len reflects only data in fragments
3696 */
3697 if (!skb_has_frag_list(skb))
3698 skb_shinfo(skb)->frag_list = new_frag;
3699
3700 new_frag->next = NULL;
3701
3702 (*last_frag)->next = new_frag;
3703 *last_frag = new_frag;
3704
3705 skb->len += new_frag->len;
3706 skb->data_len += new_frag->len;
3707 skb->truesize += new_frag->truesize;
3708}
3709
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003710static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003711{
3712 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003713
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003714 switch (__get_ctrl_sar(chan, control)) {
3715 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003716 if (chan->sdu)
3717 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003718
Mat Martineau84084a32011-07-22 14:54:00 -07003719 err = chan->ops->recv(chan->data, skb);
3720 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003721
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003722 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003723 if (chan->sdu)
3724 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003725
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003726 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003727 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003728
Mat Martineau84084a32011-07-22 14:54:00 -07003729 if (chan->sdu_len > chan->imtu) {
3730 err = -EMSGSIZE;
3731 break;
3732 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003733
Mat Martineau84084a32011-07-22 14:54:00 -07003734 if (skb->len >= chan->sdu_len)
3735 break;
3736
3737 chan->sdu = skb;
3738 chan->sdu_last_frag = skb;
3739
3740 skb = NULL;
3741 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003742 break;
3743
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003744 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003745 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003746 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003747
Mat Martineau84084a32011-07-22 14:54:00 -07003748 append_skb_frag(chan->sdu, skb,
3749 &chan->sdu_last_frag);
3750 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003751
Mat Martineau84084a32011-07-22 14:54:00 -07003752 if (chan->sdu->len >= chan->sdu_len)
3753 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003754
Mat Martineau84084a32011-07-22 14:54:00 -07003755 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003756 break;
3757
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003758 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003759 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003760 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003761
Mat Martineau84084a32011-07-22 14:54:00 -07003762 append_skb_frag(chan->sdu, skb,
3763 &chan->sdu_last_frag);
3764 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003765
Mat Martineau84084a32011-07-22 14:54:00 -07003766 if (chan->sdu->len != chan->sdu_len)
3767 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003768
Mat Martineau84084a32011-07-22 14:54:00 -07003769 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003770
Mat Martineau84084a32011-07-22 14:54:00 -07003771 if (!err) {
3772 /* Reassembly complete */
3773 chan->sdu = NULL;
3774 chan->sdu_last_frag = NULL;
3775 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003776 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003777 break;
3778 }
3779
Mat Martineau84084a32011-07-22 14:54:00 -07003780 if (err) {
3781 kfree_skb(skb);
3782 kfree_skb(chan->sdu);
3783 chan->sdu = NULL;
3784 chan->sdu_last_frag = NULL;
3785 chan->sdu_len = 0;
3786 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003787
Mat Martineau84084a32011-07-22 14:54:00 -07003788 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003789}
3790
Mat Martineau26f880d2011-07-07 09:39:01 -07003791static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003792{
Mat Martineau26f880d2011-07-07 09:39:01 -07003793 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003794
Mat Martineau26f880d2011-07-07 09:39:01 -07003795 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3796
Szymon Janc77f918b2012-01-11 10:59:48 +01003797 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003798}
3799
3800static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3801{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003802 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003803
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003804 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003805 goto done;
3806
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003807 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003808 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003809 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003810 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003811 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003812
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003813 __clear_retrans_timer(chan);
3814 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003815
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003816 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003817
3818done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003819 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3820 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003821
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003822 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003823}
3824
Mat Martineaue3281402011-07-07 09:39:02 -07003825void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003826{
Mat Martineaue3281402011-07-07 09:39:02 -07003827 if (chan->mode == L2CAP_MODE_ERTM) {
3828 if (busy)
3829 l2cap_ertm_enter_local_busy(chan);
3830 else
3831 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003832 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003833}
3834
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003835static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003836{
3837 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003838 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003839
Mat Martineaue3281402011-07-07 09:39:02 -07003840 while ((skb = skb_peek(&chan->srej_q)) &&
3841 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3842 int err;
3843
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003844 if (bt_cb(skb)->tx_seq != tx_seq)
3845 break;
3846
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003847 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003848 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003849 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003850
3851 if (err < 0) {
3852 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3853 break;
3854 }
3855
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003856 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3857 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003858 }
3859}
3860
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003861static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003862{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003863 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003864 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003865
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003866 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003867 if (l->tx_seq == tx_seq) {
3868 list_del(&l->list);
3869 kfree(l);
3870 return;
3871 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003872 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003873 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003874 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003875 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003876 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003877 }
3878}
3879
Szymon Jancaef89f22011-11-16 09:32:18 +01003880static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003881{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003882 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003883 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003884
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003885 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003886 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003887 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003888 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003889
3890 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003891 if (!new)
3892 return -ENOMEM;
3893
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003894 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003895
3896 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3897
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003898 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003899 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003900
3901 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003902
3903 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003904}
3905
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003906static 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 -03003907{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003908 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003909 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003910 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003911 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003912 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003913 int err = 0;
3914
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003915 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 -03003916 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003917
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003918 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003919 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003920 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003921 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003922 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003923 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003924 }
3925
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003926 chan->expected_ack_seq = req_seq;
3927 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003928
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003929 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003930
3931 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003932 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003933 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003934 goto drop;
3935 }
3936
Szymon Janc77f918b2012-01-11 10:59:48 +01003937 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3938 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3939 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003940 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003941 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003942
Mat Martineau02f1b642011-06-29 14:35:19 -07003943 if (tx_seq == chan->expected_tx_seq)
3944 goto expected;
3945
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003946 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003947 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003948
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003949 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003950 struct srej_list, list);
3951 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003952 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003953 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003954
3955 list_del(&first->list);
3956 kfree(first);
3957
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003958 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003959 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003960 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003961 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003962 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003963 }
3964 } else {
3965 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003966
3967 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003968 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003969 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003970
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003971 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003972 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003973 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003974 return 0;
3975 }
3976 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003977
3978 err = l2cap_send_srejframe(chan, tx_seq);
3979 if (err < 0) {
3980 l2cap_send_disconn_req(chan->conn, chan, -err);
3981 return err;
3982 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003983 }
3984 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003985 expected_tx_seq_offset = __seq_offset(chan,
3986 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003987
3988 /* duplicated tx_seq */
3989 if (tx_seq_offset < expected_tx_seq_offset)
3990 goto drop;
3991
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003992 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003993
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003994 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003995
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003996 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003997 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003998
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003999 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004000 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004001
Szymon Janc0ef3ef02012-01-11 10:59:46 +01004002 /* Set P-bit only if there are some I-frames to ack. */
4003 if (__clear_ack_timer(chan))
4004 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03004005
Szymon Jancaef89f22011-11-16 09:32:18 +01004006 err = l2cap_send_srejframe(chan, tx_seq);
4007 if (err < 0) {
4008 l2cap_send_disconn_req(chan->conn, chan, -err);
4009 return err;
4010 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004011 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004012 return 0;
4013
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004014expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004015 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004016
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004017 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03004018 bt_cb(skb)->tx_seq = tx_seq;
4019 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004020 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004021 return 0;
4022 }
4023
Mat Martineau84084a32011-07-22 14:54:00 -07004024 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004025 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4026
Mat Martineaue3281402011-07-07 09:39:02 -07004027 if (err < 0) {
4028 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4029 return err;
4030 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03004031
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004032 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004033 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004034 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03004035 }
4036
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03004037
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004038 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
4039 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004040 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03004041 else
4042 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03004043
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004044 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03004045
4046drop:
4047 kfree_skb(skb);
4048 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004049}
4050
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004051static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004052{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004053 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004054 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004055
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004056 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004057 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004058
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004059 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004060 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4061 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4062 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004063 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004064 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004065
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004066 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004067 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004068 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004069 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004070 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004071
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004072 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004073 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004074
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004075 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004076 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004077
4078 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004079 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004080 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004081 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004082
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004083 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4084 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004085 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004086 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004087 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004088 }
4089}
4090
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004091static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004092{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004093 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004094
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004095 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004096
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004097 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004098
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004099 chan->expected_ack_seq = tx_seq;
4100 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004101
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004102 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004103 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004104 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004105 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004106 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004107
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004108 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4109 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004110 }
4111}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004112static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004113{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004114 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004115
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004116 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004117
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004118 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004119
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004120 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004121 chan->expected_ack_seq = tx_seq;
4122 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004123
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004124 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004125 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004126
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004127 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004128
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004129 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004130 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004131 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004132 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004133 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004134 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004135 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004136 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004137 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004138 l2cap_retransmit_one_frame(chan, tx_seq);
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. Padovane2ab4352011-06-10 21:28:49 -03004141 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004142 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004143 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004144 }
4145 }
4146}
4147
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004148static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004149{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004150 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004151
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004152 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004153
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004154 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004155 chan->expected_ack_seq = tx_seq;
4156 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004157
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004158 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004159 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004160
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004161 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004162 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004163 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004164 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004165 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004166 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004167
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004168 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004169 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004170 } else {
4171 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4172 l2cap_send_sframe(chan, rx_control);
4173 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004174}
4175
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004176static 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 -03004177{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004178 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004179
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004180 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004181 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004182 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004183 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004184 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004185 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004186 }
4187
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004188 switch (__get_ctrl_super(chan, rx_control)) {
4189 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004190 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004191 break;
4192
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004193 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004194 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004195 break;
4196
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004197 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004198 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004199 break;
4200
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004201 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004202 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004203 break;
4204 }
4205
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004206 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004207 return 0;
4208}
4209
Szymon Janccad8f1d02012-01-23 10:06:05 +01004210static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004211{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004212 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004213 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004214 int len, next_tx_seq_offset, req_seq_offset;
4215
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004216 control = __get_control(chan, skb->data);
4217 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004218 len = skb->len;
4219
4220 /*
4221 * We can just drop the corrupted I-frame here.
4222 * Receiver will miss it and start proper recovery
4223 * procedures and ask retransmission.
4224 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004225 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004226 goto drop;
4227
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004228 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004229 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004230
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004231 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004232 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004233
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004234 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004235 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004236 goto drop;
4237 }
4238
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004239 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004240
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004241 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4242
4243 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4244 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004245
4246 /* check for invalid req-seq */
4247 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004248 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004249 goto drop;
4250 }
4251
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004252 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004253 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004254 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004255 goto drop;
4256 }
4257
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004258 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004259 } else {
4260 if (len != 0) {
4261 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004262 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004263 goto drop;
4264 }
4265
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004266 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004267 }
4268
4269 return 0;
4270
4271drop:
4272 kfree_skb(skb);
4273 return 0;
4274}
4275
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4277{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004278 struct l2cap_chan *chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004279 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004280 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004281 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004282
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004283 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004284 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 BT_DBG("unknown cid 0x%4.4x", cid);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004286 /* Drop packet and return */
Dan Carpenter33790132012-02-28 09:52:46 +03004287 kfree_skb(skb);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004288 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 }
4290
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004291 l2cap_chan_lock(chan);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004292
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004293 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004295 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 goto drop;
4297
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004298 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004299 case L2CAP_MODE_BASIC:
4300 /* If socket recv buffers overflows we drop data here
4301 * which is *bad* because L2CAP has to be reliable.
4302 * But we don't have any other choice. L2CAP doesn't
4303 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004305 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004306 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004308 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004309 goto done;
4310 break;
4311
4312 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004313 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004314
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004315 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004316
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004317 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004318 control = __get_control(chan, skb->data);
4319 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004320 len = skb->len;
4321
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004322 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004323 goto drop;
4324
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004325 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004326 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004327
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004328 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004329 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004330
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004331 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004332 goto drop;
4333
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004334 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004335
Mat Martineau84084a32011-07-22 14:54:00 -07004336 if (chan->expected_tx_seq != tx_seq) {
4337 /* Frame(s) missing - must discard partial SDU */
4338 kfree_skb(chan->sdu);
4339 chan->sdu = NULL;
4340 chan->sdu_last_frag = NULL;
4341 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004342
Mat Martineau84084a32011-07-22 14:54:00 -07004343 /* TODO: Notify userland of missing data */
4344 }
4345
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004346 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004347
4348 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4349 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004350
4351 goto done;
4352
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004353 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004354 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004355 break;
4356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357
4358drop:
4359 kfree_skb(skb);
4360
4361done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004362 l2cap_chan_unlock(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +02004363
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 return 0;
4365}
4366
Al Viro8e036fc2007-07-29 00:16:36 -07004367static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004369 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004371 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4372 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373 goto drop;
4374
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004375 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004377 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 goto drop;
4379
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004380 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 goto drop;
4382
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004383 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004384 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385
4386drop:
4387 kfree_skb(skb);
4388
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 return 0;
4390}
4391
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004392static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4393{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004394 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004395
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004396 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4397 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004398 goto drop;
4399
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004400 BT_DBG("chan %p, len %d", chan, skb->len);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004401
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004402 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004403 goto drop;
4404
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004405 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004406 goto drop;
4407
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004408 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004409 return 0;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004410
4411drop:
4412 kfree_skb(skb);
4413
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004414 return 0;
4415}
4416
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4418{
4419 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004420 u16 cid, len;
4421 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422
4423 skb_pull(skb, L2CAP_HDR_SIZE);
4424 cid = __le16_to_cpu(lh->cid);
4425 len = __le16_to_cpu(lh->len);
4426
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004427 if (len != skb->len) {
4428 kfree_skb(skb);
4429 return;
4430 }
4431
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4433
4434 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004435 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004436 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 l2cap_sig_channel(conn, skb);
4438 break;
4439
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004440 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004441 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442 skb_pull(skb, 2);
4443 l2cap_conless_channel(conn, psm, skb);
4444 break;
4445
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004446 case L2CAP_CID_LE_DATA:
4447 l2cap_att_channel(conn, cid, skb);
4448 break;
4449
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004450 case L2CAP_CID_SMP:
4451 if (smp_sig_channel(conn, skb))
4452 l2cap_conn_del(conn->hcon, EACCES);
4453 break;
4454
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 default:
4456 l2cap_data_channel(conn, cid, skb);
4457 break;
4458 }
4459}
4460
4461/* ---- L2CAP interface with lower layer (HCI) ---- */
4462
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004463int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464{
4465 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004466 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4469
4470 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004471 read_lock(&chan_list_lock);
4472 list_for_each_entry(c, &chan_list, global_l) {
4473 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004474
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004475 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 continue;
4477
4478 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004479 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004480 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004481 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004483 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4484 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004485 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004486 lm2 |= HCI_LM_MASTER;
4487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004489 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490
4491 return exact ? lm1 : lm2;
4492}
4493
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004494int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495{
Marcel Holtmann01394182006-07-03 10:02:46 +02004496 struct l2cap_conn *conn;
4497
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4499
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 conn = l2cap_conn_add(hcon, status);
4502 if (conn)
4503 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004504 } else
Joe Perchese1750722011-06-29 18:18:29 -07004505 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506
4507 return 0;
4508}
4509
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004510int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004511{
4512 struct l2cap_conn *conn = hcon->l2cap_data;
4513
4514 BT_DBG("hcon %p", hcon);
4515
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004516 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004517 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004518 return conn->disc_reason;
4519}
4520
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004521int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522{
4523 BT_DBG("hcon %p reason %d", hcon, reason);
4524
Joe Perchese1750722011-06-29 18:18:29 -07004525 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 return 0;
4527}
4528
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004529static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004530{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004531 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004532 return;
4533
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004534 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004535 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004536 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004537 __set_chan_timer(chan,
4538 msecs_to_jiffies(L2CAP_ENC_TIMEOUT));
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004539 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004540 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004541 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004542 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004543 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004544 }
4545}
4546
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004547int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004549 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004550 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551
Marcel Holtmann01394182006-07-03 10:02:46 +02004552 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004554
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 BT_DBG("conn %p", conn);
4556
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004557 if (hcon->type == LE_LINK) {
4558 smp_distribute_keys(conn, 0);
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02004559 cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004560 }
4561
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004562 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004564 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004565 l2cap_chan_lock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004566
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004567 BT_DBG("chan->scid %d", chan->scid);
4568
4569 if (chan->scid == L2CAP_CID_LE_DATA) {
4570 if (!status && encrypt) {
4571 chan->sec_level = hcon->sec_level;
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02004572 l2cap_chan_ready(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004573 }
4574
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004575 l2cap_chan_unlock(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004576 continue;
4577 }
4578
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004579 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004580 l2cap_chan_unlock(chan);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004581 continue;
4582 }
4583
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004584 if (!status && (chan->state == BT_CONNECTED ||
4585 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004586 l2cap_check_encryption(chan, encrypt);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004587 l2cap_chan_unlock(chan);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004588 continue;
4589 }
4590
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004591 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004592 if (!status) {
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +02004593 l2cap_send_conn_req(chan);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004594 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004595 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004596 __set_chan_timer(chan,
4597 msecs_to_jiffies(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);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004620 __set_chan_timer(chan,
4621 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004622 res = L2CAP_CR_SEC_BLOCK;
4623 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004624 }
4625
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004626 release_sock(sk);
4627
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004628 rsp.scid = cpu_to_le16(chan->dcid);
4629 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004630 rsp.result = cpu_to_le16(res);
4631 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004632 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4633 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 }
4635
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004636 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637 }
4638
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004639 mutex_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004640
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 return 0;
4642}
4643
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004644int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645{
4646 struct l2cap_conn *conn = hcon->l2cap_data;
4647
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004648 if (!conn)
4649 conn = l2cap_conn_add(hcon, 0);
4650
4651 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 goto drop;
4653
4654 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4655
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004656 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004658 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004659 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660 int len;
4661
4662 if (conn->rx_len) {
4663 BT_ERR("Unexpected start frame (len %d)", skb->len);
4664 kfree_skb(conn->rx_skb);
4665 conn->rx_skb = NULL;
4666 conn->rx_len = 0;
4667 l2cap_conn_unreliable(conn, ECOMM);
4668 }
4669
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004670 /* Start fragment always begin with Basic L2CAP header */
4671 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 BT_ERR("Frame is too short (len %d)", skb->len);
4673 l2cap_conn_unreliable(conn, ECOMM);
4674 goto drop;
4675 }
4676
4677 hdr = (struct l2cap_hdr *) skb->data;
4678 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004679 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680
4681 if (len == skb->len) {
4682 /* Complete frame received */
4683 l2cap_recv_frame(conn, skb);
4684 return 0;
4685 }
4686
4687 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4688
4689 if (skb->len > len) {
4690 BT_ERR("Frame is too long (len %d, expected len %d)",
4691 skb->len, len);
4692 l2cap_conn_unreliable(conn, ECOMM);
4693 goto drop;
4694 }
4695
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004696 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004697
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004698 if (chan && chan->sk) {
4699 struct sock *sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004700 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004701
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004702 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004703 BT_ERR("Frame exceeding recv MTU (len %d, "
4704 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004705 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004706 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004707 l2cap_conn_unreliable(conn, ECOMM);
4708 goto drop;
4709 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004710 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004711 }
4712
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004714 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4715 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716 goto drop;
4717
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004718 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004719 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 conn->rx_len = len - skb->len;
4721 } else {
4722 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4723
4724 if (!conn->rx_len) {
4725 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4726 l2cap_conn_unreliable(conn, ECOMM);
4727 goto drop;
4728 }
4729
4730 if (skb->len > conn->rx_len) {
4731 BT_ERR("Fragment is too long (len %d, expected %d)",
4732 skb->len, conn->rx_len);
4733 kfree_skb(conn->rx_skb);
4734 conn->rx_skb = NULL;
4735 conn->rx_len = 0;
4736 l2cap_conn_unreliable(conn, ECOMM);
4737 goto drop;
4738 }
4739
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004740 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004741 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 conn->rx_len -= skb->len;
4743
4744 if (!conn->rx_len) {
4745 /* Complete frame received */
4746 l2cap_recv_frame(conn, conn->rx_skb);
4747 conn->rx_skb = NULL;
4748 }
4749 }
4750
4751drop:
4752 kfree_skb(skb);
4753 return 0;
4754}
4755
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004756static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004758 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004760 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004762 list_for_each_entry(c, &chan_list, global_l) {
4763 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004765 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 +01004766 batostr(&bt_sk(sk)->src),
4767 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004768 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004769 c->scid, c->dcid, c->imtu, c->omtu,
4770 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004771 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004773 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004774
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004775 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776}
4777
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004778static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4779{
4780 return single_open(file, l2cap_debugfs_show, inode->i_private);
4781}
4782
4783static const struct file_operations l2cap_debugfs_fops = {
4784 .open = l2cap_debugfs_open,
4785 .read = seq_read,
4786 .llseek = seq_lseek,
4787 .release = single_release,
4788};
4789
4790static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004792int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004793{
4794 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004795
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004796 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 if (err < 0)
4798 return err;
4799
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004800 if (bt_debugfs) {
4801 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4802 bt_debugfs, NULL, &l2cap_debugfs_fops);
4803 if (!l2cap_debugfs)
4804 BT_ERR("Failed to create L2CAP debug file");
4805 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808}
4809
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004810void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004812 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004813 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814}
4815
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004816module_param(disable_ertm, bool, 0644);
4817MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");