blob: 4b66cad3ee3d3bc93fd817206f234109a0056e8a [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Gustavo F. Padovan590051d2011-12-18 13:39:33 -02006 Copyright (C) 2011 ProFUSION Embedded Systems
Linus Torvalds1da177e2005-04-16 15:20:36 -07007
8 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation;
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
17 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090023 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 SOFTWARE IS DISCLAIMED.
26*/
27
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020028/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31
32#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080033#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/errno.h>
35#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/sched.h>
37#include <linux/slab.h>
38#include <linux/poll.h>
39#include <linux/fcntl.h>
40#include <linux/init.h>
41#include <linux/interrupt.h>
42#include <linux/socket.h>
43#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080045#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010046#include <linux/debugfs.h>
47#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030048#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030049#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <net/sock.h>
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/unaligned.h>
53
54#include <net/bluetooth/bluetooth.h>
55#include <net/bluetooth/hci_core.h>
56#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030057#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Rusty Russelleb939922011-12-19 14:08:01 +000059bool disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020060
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070061static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070062static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Johannes Bergb5ad8b72011-06-01 08:54:45 +020064static LIST_HEAD(chan_list);
65static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
68 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030069static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
70 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030071static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030072static void l2cap_send_disconn_req(struct l2cap_conn *conn,
73 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Marcel Holtmann01394182006-07-03 10:02:46 +020075/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030076
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030077static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020078{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020079 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030080
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020081 list_for_each_entry(c, &conn->chan_l, list) {
82 if (c->dcid == cid)
83 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020084 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020085 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020086}
87
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030088static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020089{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020090 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030091
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020092 list_for_each_entry(c, &conn->chan_l, list) {
93 if (c->scid == cid)
94 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020095 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020096 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020097}
98
99/* Find channel with given SCID.
100 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300101static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200102{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300103 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300104
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200105 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300106 c = __l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200107 mutex_unlock(&conn->chan_lock);
108
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300109 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200110}
111
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300112static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200113{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200114 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300115
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200116 list_for_each_entry(c, &conn->chan_l, list) {
117 if (c->ident == ident)
118 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200119 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200120 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200121}
122
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300123static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200124{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300125 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300126
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200127 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300128 c = __l2cap_get_chan_by_ident(conn, ident);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200129 mutex_unlock(&conn->chan_lock);
130
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300131 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200132}
133
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300134static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300135{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300136 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300137
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300138 list_for_each_entry(c, &chan_list, global_l) {
139 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100140 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300141 }
Szymon Janc250938c2011-11-16 09:32:22 +0100142 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300143}
144
145int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
146{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300147 int err;
148
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200149 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300150
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300151 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300152 err = -EADDRINUSE;
153 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300154 }
155
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300156 if (psm) {
157 chan->psm = psm;
158 chan->sport = psm;
159 err = 0;
160 } else {
161 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300162
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300163 err = -EINVAL;
164 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300165 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300166 chan->psm = cpu_to_le16(p);
167 chan->sport = cpu_to_le16(p);
168 err = 0;
169 break;
170 }
171 }
172
173done:
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200174 write_unlock(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300175 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300176}
177
178int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
179{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200180 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300181
182 chan->scid = scid;
183
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200184 write_unlock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300185
186 return 0;
187}
188
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300189static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200190{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300191 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200192
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300193 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300194 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200195 return cid;
196 }
197
198 return 0;
199}
200
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200201static void __l2cap_state_change(struct l2cap_chan *chan, int state)
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300202{
Andrei Emeltchenko42d2d872012-02-17 11:40:57 +0200203 BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200204 state_to_string(state));
205
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300206 chan->state = state;
207 chan->ops->state_change(chan->data, state);
208}
209
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200210static void l2cap_state_change(struct l2cap_chan *chan, int state)
211{
212 struct sock *sk = chan->sk;
213
214 lock_sock(sk);
215 __l2cap_state_change(chan, state);
216 release_sock(sk);
217}
218
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200219static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
220{
221 struct sock *sk = chan->sk;
222
223 sk->sk_err = err;
224}
225
226static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
227{
228 struct sock *sk = chan->sk;
229
230 lock_sock(sk);
231 __l2cap_chan_set_err(chan, err);
232 release_sock(sk);
233}
234
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300235static void l2cap_chan_timeout(struct work_struct *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300236{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300237 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
238 chan_timer.work);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200239 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300240 int reason;
241
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200242 BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300243
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200244 mutex_lock(&conn->chan_lock);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200245 l2cap_chan_lock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300246
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300247 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300248 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300249 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300250 chan->sec_level != BT_SECURITY_SDP)
251 reason = ECONNREFUSED;
252 else
253 reason = ETIMEDOUT;
254
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300255 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300256
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200257 l2cap_chan_unlock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300258
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300259 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200260 mutex_unlock(&conn->chan_lock);
261
Ulisses Furquim371fd832011-12-21 20:02:36 -0200262 l2cap_chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300263}
264
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300265struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200266{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300267 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200268
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300269 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
270 if (!chan)
271 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200272
Andrei Emeltchenkoc03b3552012-02-21 12:54:56 +0200273 mutex_init(&chan->lock);
274
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300275 chan->sk = sk;
276
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200277 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300278 list_add(&chan->global_l, &chan_list);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200279 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300280
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300281 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300282
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300283 chan->state = BT_OPEN;
284
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300285 atomic_set(&chan->refcnt, 1);
286
Szymon Jancabc545b2011-11-03 16:05:44 +0100287 BT_DBG("sk %p chan %p", sk, chan);
288
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300289 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200290}
291
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300292void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300293{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200294 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300295 list_del(&chan->global_l);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200296 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300297
Ulisses Furquim371fd832011-12-21 20:02:36 -0200298 l2cap_chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300299}
300
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200301void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200302{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300303 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Andrei Emeltchenko097db762012-03-09 14:16:17 +0200304 __le16_to_cpu(chan->psm), chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200305
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200306 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100307
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300308 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200309
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200310 switch (chan->chan_type) {
311 case L2CAP_CHAN_CONN_ORIENTED:
Ville Tervob62f3282011-02-10 22:38:50 -0300312 if (conn->hcon->type == LE_LINK) {
313 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300314 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300315 chan->scid = L2CAP_CID_LE_DATA;
316 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300317 } else {
318 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300319 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300320 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300321 }
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200322 break;
323
324 case L2CAP_CHAN_CONN_LESS:
Marcel Holtmann01394182006-07-03 10:02:46 +0200325 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300326 chan->scid = L2CAP_CID_CONN_LESS;
327 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300328 chan->omtu = L2CAP_DEFAULT_MTU;
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200329 break;
330
331 default:
Marcel Holtmann01394182006-07-03 10:02:46 +0200332 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300333 chan->scid = L2CAP_CID_SIGNALING;
334 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300335 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200336 }
337
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300338 chan->local_id = L2CAP_BESTEFFORT_ID;
339 chan->local_stype = L2CAP_SERV_BESTEFFORT;
340 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
341 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
342 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
343 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
344
Ulisses Furquim371fd832011-12-21 20:02:36 -0200345 l2cap_chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300346
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200347 list_add(&chan->list, &conn->chan_l);
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200348}
349
350void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
351{
352 mutex_lock(&conn->chan_lock);
353 __l2cap_chan_add(conn, chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200354 mutex_unlock(&conn->chan_lock);
Marcel Holtmann01394182006-07-03 10:02:46 +0200355}
356
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300357static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200358{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300359 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300360 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200361 struct sock *parent = bt_sk(sk)->parent;
362
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300363 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200364
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300365 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200366
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900367 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300368 /* Delete from channel list */
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200369 list_del(&chan->list);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200370
Ulisses Furquim371fd832011-12-21 20:02:36 -0200371 l2cap_chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300372
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300373 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200374 hci_conn_put(conn->hcon);
375 }
376
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200377 lock_sock(sk);
378
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200379 __l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200380 sock_set_flag(sk, SOCK_ZAPPED);
381
382 if (err)
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200383 __l2cap_chan_set_err(chan, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200384
385 if (parent) {
386 bt_accept_unlink(sk);
387 parent->sk_data_ready(parent, 0);
388 } else
389 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300390
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200391 release_sock(sk);
392
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300393 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
394 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300395 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300396
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300397 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300398
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300399 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300400 struct srej_list *l, *tmp;
401
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300402 __clear_retrans_timer(chan);
403 __clear_monitor_timer(chan);
404 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300405
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300406 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300407
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300408 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300409 list_del(&l->list);
410 kfree(l);
411 }
412 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200413}
414
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300415static void l2cap_chan_cleanup_listen(struct sock *parent)
416{
417 struct sock *sk;
418
419 BT_DBG("parent %p", parent);
420
421 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300422 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300423 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200424
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200425 l2cap_chan_lock(chan);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300426 __clear_chan_timer(chan);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300427 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200428 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200429
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300430 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300431 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300432}
433
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300434void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300435{
436 struct l2cap_conn *conn = chan->conn;
437 struct sock *sk = chan->sk;
438
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200439 BT_DBG("chan %p state %s sk %p", chan,
440 state_to_string(chan->state), sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300441
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300442 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300443 case BT_LISTEN:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200444 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300445 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300446
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200447 __l2cap_state_change(chan, BT_CLOSED);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300448 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200449 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300450 break;
451
452 case BT_CONNECTED:
453 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300454 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300455 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300456 __clear_chan_timer(chan);
457 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300458 l2cap_send_disconn_req(conn, chan, reason);
459 } else
460 l2cap_chan_del(chan, reason);
461 break;
462
463 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300464 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300465 conn->hcon->type == ACL_LINK) {
466 struct l2cap_conn_rsp rsp;
467 __u16 result;
468
469 if (bt_sk(sk)->defer_setup)
470 result = L2CAP_CR_SEC_BLOCK;
471 else
472 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300473 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300474
475 rsp.scid = cpu_to_le16(chan->dcid);
476 rsp.dcid = cpu_to_le16(chan->scid);
477 rsp.result = cpu_to_le16(result);
478 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
479 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
480 sizeof(rsp), &rsp);
481 }
482
483 l2cap_chan_del(chan, reason);
484 break;
485
486 case BT_CONNECT:
487 case BT_DISCONN:
488 l2cap_chan_del(chan, reason);
489 break;
490
491 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200492 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300493 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200494 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300495 break;
496 }
497}
498
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300499static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530500{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300501 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300502 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530503 case BT_SECURITY_HIGH:
504 return HCI_AT_DEDICATED_BONDING_MITM;
505 case BT_SECURITY_MEDIUM:
506 return HCI_AT_DEDICATED_BONDING;
507 default:
508 return HCI_AT_NO_BONDING;
509 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300510 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300511 if (chan->sec_level == BT_SECURITY_LOW)
512 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530513
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300514 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530515 return HCI_AT_NO_BONDING_MITM;
516 else
517 return HCI_AT_NO_BONDING;
518 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300519 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530520 case BT_SECURITY_HIGH:
521 return HCI_AT_GENERAL_BONDING_MITM;
522 case BT_SECURITY_MEDIUM:
523 return HCI_AT_GENERAL_BONDING;
524 default:
525 return HCI_AT_NO_BONDING;
526 }
527 }
528}
529
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200530/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200531int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200532{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300533 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100534 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200535
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300536 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100537
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300538 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200539}
540
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200541static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200542{
543 u8 id;
544
545 /* Get next available identificator.
546 * 1 - 128 are used by kernel.
547 * 129 - 199 are reserved.
548 * 200 - 254 are used by utilities like l2ping, etc.
549 */
550
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200551 spin_lock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200552
553 if (++conn->tx_ident > 128)
554 conn->tx_ident = 1;
555
556 id = conn->tx_ident;
557
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200558 spin_unlock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200559
560 return id;
561}
562
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300563static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200564{
565 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200566 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200567
568 BT_DBG("code 0x%2.2x", code);
569
570 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300571 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200572
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200573 if (lmp_no_flush_capable(conn->hcon->hdev))
574 flags = ACL_START_NO_FLUSH;
575 else
576 flags = ACL_START;
577
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700578 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200579 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700580
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200581 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200582}
583
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200584static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
585{
586 struct hci_conn *hcon = chan->conn->hcon;
587 u16 flags;
588
589 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
590 skb->priority);
591
592 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
593 lmp_no_flush_capable(hcon->hdev))
594 flags = ACL_START_NO_FLUSH;
595 else
596 flags = ACL_START;
597
598 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
599 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600}
601
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300602static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300603{
604 struct sk_buff *skb;
605 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300606 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300607 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300608
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300609 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300610 return;
611
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300612 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
613 hlen = L2CAP_EXT_HDR_SIZE;
614 else
615 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300616
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300617 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300618 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300619
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300620 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300621
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300622 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300623
624 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300625
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300626 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300627 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300628
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300629 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300630 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300631
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300632 skb = bt_skb_alloc(count, GFP_ATOMIC);
633 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300634 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300635
636 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300637 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300638 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300639
640 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300641
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300642 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300643 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
644 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300645 }
646
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200647 skb->priority = HCI_PRIO_MAX;
648 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300649}
650
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300651static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300652{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300653 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300654 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300655 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300656 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300657 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300658
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300659 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300660
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300661 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300662}
663
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300664static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300665{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300666 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300667}
668
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200669static void l2cap_send_conn_req(struct l2cap_chan *chan)
670{
671 struct l2cap_conn *conn = chan->conn;
672 struct l2cap_conn_req req;
673
674 req.scid = cpu_to_le16(chan->scid);
675 req.psm = chan->psm;
676
677 chan->ident = l2cap_get_ident(conn);
678
679 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
680
681 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
682}
683
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300684static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200685{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300686 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200687
688 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100689 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
690 return;
691
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200692 if (l2cap_chan_check_security(chan) &&
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200693 __l2cap_no_conn_pending(chan))
694 l2cap_send_conn_req(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200695 } else {
696 struct l2cap_info_req req;
697 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
698
699 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
700 conn->info_ident = l2cap_get_ident(conn);
701
Marcel Holtmannba13ccd2012-03-01 14:25:33 -0800702 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200703
704 l2cap_send_cmd(conn, conn->info_ident,
705 L2CAP_INFO_REQ, sizeof(req), &req);
706 }
707}
708
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300709static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
710{
711 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300712 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300713 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
714
715 switch (mode) {
716 case L2CAP_MODE_ERTM:
717 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
718 case L2CAP_MODE_STREAMING:
719 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
720 default:
721 return 0x00;
722 }
723}
724
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300725static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300726{
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200727 struct sock *sk = chan->sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300728 struct l2cap_disconn_req req;
729
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300730 if (!conn)
731 return;
732
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300733 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300734 __clear_retrans_timer(chan);
735 __clear_monitor_timer(chan);
736 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300737 }
738
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300739 req.dcid = cpu_to_le16(chan->dcid);
740 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300741 l2cap_send_cmd(conn, l2cap_get_ident(conn),
742 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300743
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200744 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200745 __l2cap_state_change(chan, BT_DISCONN);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200746 __l2cap_chan_set_err(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200747 release_sock(sk);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300748}
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200751static void l2cap_conn_start(struct l2cap_conn *conn)
752{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200753 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200754
755 BT_DBG("conn %p", conn);
756
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200757 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200758
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200759 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300760 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300761
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200762 l2cap_chan_lock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200763
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300764 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200765 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200766 continue;
767 }
768
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300769 if (chan->state == BT_CONNECT) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200770 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300771 !__l2cap_no_conn_pending(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200772 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300773 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200774 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300775
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300776 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
777 && test_bit(CONF_STATE2_DEVICE,
778 &chan->conf_state)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300779 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200780 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300781 continue;
782 }
783
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200784 l2cap_send_conn_req(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300785
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300786 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200787 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300788 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300789 rsp.scid = cpu_to_le16(chan->dcid);
790 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200791
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200792 if (l2cap_chan_check_security(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200793 lock_sock(sk);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100794 if (bt_sk(sk)->defer_setup) {
795 struct sock *parent = bt_sk(sk)->parent;
796 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
797 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000798 if (parent)
799 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100800
801 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200802 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100803 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
804 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
805 }
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200806 release_sock(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200807 } else {
808 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
809 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
810 }
811
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300812 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
813 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300814
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300815 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300816 rsp.result != L2CAP_CR_SUCCESS) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200817 l2cap_chan_unlock(chan);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300818 continue;
819 }
820
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300821 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300822 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300823 l2cap_build_conf_req(chan, buf), buf);
824 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200825 }
826
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200827 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200828 }
829
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200830 mutex_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200831}
832
Ville Tervob62f3282011-02-10 22:38:50 -0300833/* Find socket with cid and source bdaddr.
834 * Returns closest match, locked.
835 */
Andrei Emeltchenkod9b88702012-03-12 12:13:08 +0200836static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
837 bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300838{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300839 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300840
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300841 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300842
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300843 list_for_each_entry(c, &chan_list, global_l) {
844 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300845
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300846 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300847 continue;
848
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300849 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300850 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300851 if (!bacmp(&bt_sk(sk)->src, src)) {
852 read_unlock(&chan_list_lock);
853 return c;
854 }
Ville Tervob62f3282011-02-10 22:38:50 -0300855
856 /* Closest match */
857 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300858 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300859 }
860 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300861
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300862 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300863
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300864 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300865}
866
867static void l2cap_le_conn_ready(struct l2cap_conn *conn)
868{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300869 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300870 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300871
872 BT_DBG("");
873
874 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300875 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300876 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300877 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300878 return;
879
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300880 parent = pchan->sk;
881
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300882 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300883
Ville Tervob62f3282011-02-10 22:38:50 -0300884 /* Check for backlog size */
885 if (sk_acceptq_is_full(parent)) {
886 BT_DBG("backlog full %d", parent->sk_ack_backlog);
887 goto clean;
888 }
889
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300890 chan = pchan->ops->new_connection(pchan->data);
891 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300892 goto clean;
893
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300894 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300895
Ville Tervob62f3282011-02-10 22:38:50 -0300896 hci_conn_hold(conn->hcon);
897
Ville Tervob62f3282011-02-10 22:38:50 -0300898 bacpy(&bt_sk(sk)->src, conn->src);
899 bacpy(&bt_sk(sk)->dst, conn->dst);
900
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300901 bt_accept_enqueue(parent, sk);
902
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200903 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300904
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300905 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300906
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200907 __l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300908 parent->sk_data_ready(parent, 0);
909
Ville Tervob62f3282011-02-10 22:38:50 -0300910clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300911 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300912}
913
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200914static void l2cap_chan_ready(struct l2cap_chan *chan)
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300915{
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200916 struct sock *sk = chan->sk;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200917 struct sock *parent;
918
919 lock_sock(sk);
920
921 parent = bt_sk(sk)->parent;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300922
923 BT_DBG("sk %p, parent %p", sk, parent);
924
925 chan->conf_state = 0;
926 __clear_chan_timer(chan);
927
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200928 __l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300929 sk->sk_state_change(sk);
930
931 if (parent)
932 parent->sk_data_ready(parent, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200933
934 release_sock(sk);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300935}
936
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200937static void l2cap_conn_ready(struct l2cap_conn *conn)
938{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300939 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200940
941 BT_DBG("conn %p", conn);
942
Ville Tervob62f3282011-02-10 22:38:50 -0300943 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
944 l2cap_le_conn_ready(conn);
945
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300946 if (conn->hcon->out && conn->hcon->type == LE_LINK)
947 smp_conn_security(conn, conn->hcon->pending_sec_level);
948
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200949 mutex_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200950
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200951 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300952
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200953 l2cap_chan_lock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200954
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300955 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300956 if (smp_conn_security(conn, chan->sec_level))
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200957 l2cap_chan_ready(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300958
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300959 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200960 struct sock *sk = chan->sk;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300961 __clear_chan_timer(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200962 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200963 __l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200964 sk->sk_state_change(sk);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200965 release_sock(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300966
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300967 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300968 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200969
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200970 l2cap_chan_unlock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200971 }
972
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200973 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200974}
975
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200976/* Notify sockets that we cannot guaranty reliability anymore */
977static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
978{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300979 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200980
981 BT_DBG("conn %p", conn);
982
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200983 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200984
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200985 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300986 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200987 __l2cap_chan_set_err(chan, err);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200988 }
989
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200990 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200991}
992
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200993static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200994{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200995 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200996 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200997
Marcel Holtmann984947d2009-02-06 23:35:19 +0100998 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100999 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01001000
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001001 l2cap_conn_start(conn);
1002}
1003
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001004static void l2cap_conn_del(struct hci_conn *hcon, int err)
1005{
1006 struct l2cap_conn *conn = hcon->l2cap_data;
1007 struct l2cap_chan *chan, *l;
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001008
1009 if (!conn)
1010 return;
1011
1012 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1013
1014 kfree_skb(conn->rx_skb);
1015
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001016 mutex_lock(&conn->chan_lock);
1017
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001018 /* Kill channels */
1019 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001020 l2cap_chan_lock(chan);
1021
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001022 l2cap_chan_del(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001023
1024 l2cap_chan_unlock(chan);
1025
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001026 chan->ops->close(chan->data);
1027 }
1028
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001029 mutex_unlock(&conn->chan_lock);
1030
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001031 hci_chan_del(conn->hchan);
1032
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001033 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim127074b2012-01-30 18:26:29 -02001034 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001035
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001036 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim127074b2012-01-30 18:26:29 -02001037 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001038 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001039 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001040
1041 hcon->l2cap_data = NULL;
1042 kfree(conn);
1043}
1044
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001045static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001046{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001047 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1048 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001049
1050 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1051}
1052
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1054{
Marcel Holtmann01394182006-07-03 10:02:46 +02001055 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001056 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Marcel Holtmann01394182006-07-03 10:02:46 +02001058 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 return conn;
1060
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001061 hchan = hci_chan_create(hcon);
1062 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001065 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1066 if (!conn) {
1067 hci_chan_del(hchan);
1068 return NULL;
1069 }
1070
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 hcon->l2cap_data = conn;
1072 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001073 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001075 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001076
Ville Tervoacd7d372011-02-10 22:38:49 -03001077 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1078 conn->mtu = hcon->hdev->le_mtu;
1079 else
1080 conn->mtu = hcon->hdev->acl_mtu;
1081
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 conn->src = &hcon->hdev->bdaddr;
1083 conn->dst = &hcon->dst;
1084
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001085 conn->feat_mask = 0;
1086
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 spin_lock_init(&conn->lock);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001088 mutex_init(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001089
1090 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001092 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001093 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001094 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001095 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001096
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001097 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001098
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 return conn;
1100}
1101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104/* Find socket with psm and source bdaddr.
1105 * Returns closest match.
1106 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001107static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001109 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001111 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001112
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001113 list_for_each_entry(c, &chan_list, global_l) {
1114 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001115
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001116 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 continue;
1118
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001119 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001121 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001122 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001123 return c;
1124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125
1126 /* Closest match */
1127 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001128 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 }
1130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001132 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001133
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001134 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135}
1136
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001137int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001139 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 struct l2cap_conn *conn;
1142 struct hci_conn *hcon;
1143 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001144 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001145 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001147 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Andrei Emeltchenko097db762012-03-09 14:16:17 +02001148 __le16_to_cpu(chan->psm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001150 hdev = hci_get_route(dst, src);
1151 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 return -EHOSTUNREACH;
1153
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001154 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001156 l2cap_chan_lock(chan);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001157
1158 /* PSM must be odd and lsb of upper byte must be 0 */
1159 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1160 chan->chan_type != L2CAP_CHAN_RAW) {
1161 err = -EINVAL;
1162 goto done;
1163 }
1164
1165 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1166 err = -EINVAL;
1167 goto done;
1168 }
1169
1170 switch (chan->mode) {
1171 case L2CAP_MODE_BASIC:
1172 break;
1173 case L2CAP_MODE_ERTM:
1174 case L2CAP_MODE_STREAMING:
1175 if (!disable_ertm)
1176 break;
1177 /* fall through */
1178 default:
1179 err = -ENOTSUPP;
1180 goto done;
1181 }
1182
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001183 lock_sock(sk);
1184
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001185 switch (sk->sk_state) {
1186 case BT_CONNECT:
1187 case BT_CONNECT2:
1188 case BT_CONFIG:
1189 /* Already connecting */
1190 err = 0;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001191 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001192 goto done;
1193
1194 case BT_CONNECTED:
1195 /* Already connected */
1196 err = -EISCONN;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001197 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001198 goto done;
1199
1200 case BT_OPEN:
1201 case BT_BOUND:
1202 /* Can connect */
1203 break;
1204
1205 default:
1206 err = -EBADFD;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001207 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001208 goto done;
1209 }
1210
1211 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001212 bacpy(&bt_sk(sk)->dst, dst);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001213
1214 release_sock(sk);
1215
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001216 chan->psm = psm;
1217 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001219 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001220
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001221 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001222 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001223 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001224 else
1225 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001226 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001227
Ville Tervo30e76272011-02-22 16:10:53 -03001228 if (IS_ERR(hcon)) {
1229 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001231 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
1233 conn = l2cap_conn_add(hcon, 0);
1234 if (!conn) {
1235 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001236 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 goto done;
1238 }
1239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 /* Update source addr of the socket */
1241 bacpy(src, conn->src);
1242
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001243 l2cap_chan_unlock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001244 l2cap_chan_add(conn, chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001245 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001246
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001247 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001248 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001251 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001252 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001253 if (l2cap_chan_check_security(chan))
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001254 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001255 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001256 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 }
1258
Ville Tervo30e76272011-02-22 16:10:53 -03001259 err = 0;
1260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001262 l2cap_chan_unlock(chan);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001263 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 hci_dev_put(hdev);
1265 return err;
1266}
1267
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001268int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001269{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001270 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001271 DECLARE_WAITQUEUE(wait, current);
1272 int err = 0;
1273 int timeo = HZ/5;
1274
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001275 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001276 set_current_state(TASK_INTERRUPTIBLE);
1277 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001278 if (!timeo)
1279 timeo = HZ/5;
1280
1281 if (signal_pending(current)) {
1282 err = sock_intr_errno(timeo);
1283 break;
1284 }
1285
1286 release_sock(sk);
1287 timeo = schedule_timeout(timeo);
1288 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001289 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001290
1291 err = sock_error(sk);
1292 if (err)
1293 break;
1294 }
1295 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001296 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001297 return err;
1298}
1299
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001300static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001301{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001302 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1303 monitor_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001304
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001305 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001306
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001307 l2cap_chan_lock(chan);
1308
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001309 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001310 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001311 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001312 l2cap_chan_put(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);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001321 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001322}
1323
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001324static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001325{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001326 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1327 retrans_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001328
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001329 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001330
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001331 l2cap_chan_lock(chan);
1332
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001333 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001334 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001335
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001336 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001337
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001338 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001339
1340 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001341 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001342}
1343
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001344static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001345{
1346 struct sk_buff *skb;
1347
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001348 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001349 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001350 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001351 break;
1352
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001353 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001354 kfree_skb(skb);
1355
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001356 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001357 }
1358
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001359 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001360 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001361}
1362
Szymon Janc67c9e842011-07-28 16:24:33 +02001363static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001364{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001365 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001366 u32 control;
1367 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001368
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001369 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001370 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001371 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001372 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001373
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001374 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001375 fcs = crc16(0, (u8 *)skb->data,
1376 skb->len - L2CAP_FCS_SIZE);
1377 put_unaligned_le16(fcs,
1378 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001379 }
1380
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001381 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001382
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001383 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001384 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001385}
1386
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001387static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001388{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001389 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001390 u16 fcs;
1391 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001392
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001393 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001394 if (!skb)
1395 return;
1396
Szymon Jancd1726b62011-11-16 09:32:20 +01001397 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001398 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001399 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001400
Szymon Jancd1726b62011-11-16 09:32:20 +01001401 skb = skb_queue_next(&chan->tx_q, skb);
1402 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001403
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001404 if (chan->remote_max_tx &&
1405 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001406 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001407 return;
1408 }
1409
1410 tx_skb = skb_clone(skb, GFP_ATOMIC);
1411 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001412
1413 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001414 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001415
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001416 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001417 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001418
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001419 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001420 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001421
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001422 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001423
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001424 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001425 fcs = crc16(0, (u8 *)tx_skb->data,
1426 tx_skb->len - L2CAP_FCS_SIZE);
1427 put_unaligned_le16(fcs,
1428 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001429 }
1430
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001431 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001432}
1433
Szymon Janc67c9e842011-07-28 16:24:33 +02001434static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001435{
1436 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001437 u16 fcs;
1438 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001439 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001440
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001441 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001442 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001443
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001444 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001445
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001446 if (chan->remote_max_tx &&
1447 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001448 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001449 break;
1450 }
1451
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001452 tx_skb = skb_clone(skb, GFP_ATOMIC);
1453
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001454 bt_cb(skb)->retries++;
1455
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001456 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001457 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001458
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001459 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001460 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001461
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001462 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001463 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001464
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001465 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001466
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001467 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001468 fcs = crc16(0, (u8 *)skb->data,
1469 tx_skb->len - L2CAP_FCS_SIZE);
1470 put_unaligned_le16(fcs, skb->data +
1471 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001472 }
1473
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001474 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001475
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001476 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001477
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001478 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001479
1480 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001481
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001482 if (bt_cb(skb)->retries == 1) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001483 chan->unacked_frames++;
Szymon Janc930fa4a2012-02-07 15:43:02 +01001484
1485 if (!nsent++)
1486 __clear_ack_timer(chan);
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001487 }
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301488
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001489 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001490
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001491 if (skb_queue_is_last(&chan->tx_q, skb))
1492 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001493 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001494 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001495 }
1496
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001497 return nsent;
1498}
1499
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001500static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001501{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001502 int ret;
1503
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001504 if (!skb_queue_empty(&chan->tx_q))
1505 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001506
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001507 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001508 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001509 return ret;
1510}
1511
Szymon Jancb17e73b2012-01-11 10:59:47 +01001512static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001513{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001514 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001515
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001516 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001517
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001518 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001519 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001520 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001521 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001522 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001523 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001524
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001525 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001526 return;
1527
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001528 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001529 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001530}
1531
Szymon Jancb17e73b2012-01-11 10:59:47 +01001532static void l2cap_send_ack(struct l2cap_chan *chan)
1533{
1534 __clear_ack_timer(chan);
1535 __l2cap_send_ack(chan);
1536}
1537
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001538static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001539{
1540 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001541 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001542
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001543 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001544 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001545
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001546 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001547 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001548
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001549 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001550}
1551
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001552static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
1553 struct msghdr *msg, int len,
1554 int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001556 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001557 struct sk_buff **frag;
1558 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001560 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001561 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
1563 sent += count;
1564 len -= count;
1565
1566 /* Continuation fragments (no L2CAP header) */
1567 frag = &skb_shinfo(skb)->frag_list;
1568 while (len) {
1569 count = min_t(unsigned int, conn->mtu, len);
1570
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001571 *frag = chan->ops->alloc_skb(chan, count,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001572 msg->msg_flags & MSG_DONTWAIT,
1573 &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001574
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001576 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001577 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1578 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001580 (*frag)->priority = skb->priority;
1581
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 sent += count;
1583 len -= count;
1584
1585 frag = &(*frag)->next;
1586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
1588 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001589}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001591static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1592 struct msghdr *msg, size_t len,
1593 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001594{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001595 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001596 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001597 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001598 struct l2cap_hdr *lh;
1599
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001600 BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001601
1602 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001603
1604 skb = chan->ops->alloc_skb(chan, count + hlen,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001605 msg->msg_flags & MSG_DONTWAIT, &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001606
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001607 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001608 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001609
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001610 skb->priority = priority;
1611
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001612 /* Create L2CAP header */
1613 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001614 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001615 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko097db762012-03-09 14:16:17 +02001616 put_unaligned(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001617
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001618 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001619 if (unlikely(err < 0)) {
1620 kfree_skb(skb);
1621 return ERR_PTR(err);
1622 }
1623 return skb;
1624}
1625
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001626static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1627 struct msghdr *msg, size_t len,
1628 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001629{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001630 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001631 struct sk_buff *skb;
1632 int err, count, hlen = L2CAP_HDR_SIZE;
1633 struct l2cap_hdr *lh;
1634
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001635 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001636
1637 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001638
1639 skb = chan->ops->alloc_skb(chan, count + hlen,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001640 msg->msg_flags & MSG_DONTWAIT, &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001641
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001642 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001643 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001644
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001645 skb->priority = priority;
1646
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001647 /* Create L2CAP header */
1648 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001649 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001650 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1651
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001652 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001653 if (unlikely(err < 0)) {
1654 kfree_skb(skb);
1655 return ERR_PTR(err);
1656 }
1657 return skb;
1658}
1659
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001660static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1661 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001662 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001663{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001664 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001665 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001666 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001667 struct l2cap_hdr *lh;
1668
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001669 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001670
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001671 if (!conn)
1672 return ERR_PTR(-ENOTCONN);
1673
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001674 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1675 hlen = L2CAP_EXT_HDR_SIZE;
1676 else
1677 hlen = L2CAP_ENH_HDR_SIZE;
1678
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001679 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001680 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001681
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001682 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001683 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001684
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001685 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001686
1687 skb = chan->ops->alloc_skb(chan, count + hlen,
1688 msg->msg_flags & MSG_DONTWAIT, &err);
1689
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001690 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001691 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001692
1693 /* Create L2CAP header */
1694 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001695 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001696 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001697
1698 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1699
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001700 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001701 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001702
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001703 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001704 if (unlikely(err < 0)) {
1705 kfree_skb(skb);
1706 return ERR_PTR(err);
1707 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001708
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001709 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001710 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001711
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001712 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001713 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714}
1715
Szymon Janc67c9e842011-07-28 16:24:33 +02001716static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001717{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001718 struct sk_buff *skb;
1719 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001720 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001721 size_t size = 0;
1722
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001723 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001724 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001725 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001726 if (IS_ERR(skb))
1727 return PTR_ERR(skb);
1728
1729 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001730 len -= chan->remote_mps;
1731 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001732
1733 while (len > 0) {
1734 size_t buflen;
1735
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001736 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001737 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001738 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001739 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001740 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001741 buflen = len;
1742 }
1743
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001744 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001745 if (IS_ERR(skb)) {
1746 skb_queue_purge(&sar_queue);
1747 return PTR_ERR(skb);
1748 }
1749
1750 __skb_queue_tail(&sar_queue, skb);
1751 len -= buflen;
1752 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001753 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001754 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1755 if (chan->tx_send_head == NULL)
1756 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001757
1758 return size;
1759}
1760
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001761int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1762 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001763{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001764 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001765 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001766 int err;
1767
1768 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001769 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001770 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001771 if (IS_ERR(skb))
1772 return PTR_ERR(skb);
1773
1774 l2cap_do_send(chan, skb);
1775 return len;
1776 }
1777
1778 switch (chan->mode) {
1779 case L2CAP_MODE_BASIC:
1780 /* Check outgoing MTU */
1781 if (len > chan->omtu)
1782 return -EMSGSIZE;
1783
1784 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001785 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001786 if (IS_ERR(skb))
1787 return PTR_ERR(skb);
1788
1789 l2cap_do_send(chan, skb);
1790 err = len;
1791 break;
1792
1793 case L2CAP_MODE_ERTM:
1794 case L2CAP_MODE_STREAMING:
1795 /* Entire SDU fits into one PDU */
1796 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001797 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001798 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1799 0);
1800 if (IS_ERR(skb))
1801 return PTR_ERR(skb);
1802
1803 __skb_queue_tail(&chan->tx_q, skb);
1804
1805 if (chan->tx_send_head == NULL)
1806 chan->tx_send_head = skb;
1807
1808 } else {
1809 /* Segment SDU into multiples PDUs */
1810 err = l2cap_sar_segment_sdu(chan, msg, len);
1811 if (err < 0)
1812 return err;
1813 }
1814
1815 if (chan->mode == L2CAP_MODE_STREAMING) {
1816 l2cap_streaming_send(chan);
1817 err = len;
1818 break;
1819 }
1820
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001821 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1822 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001823 err = len;
1824 break;
1825 }
1826
1827 err = l2cap_ertm_send(chan);
1828 if (err >= 0)
1829 err = len;
1830
1831 break;
1832
1833 default:
1834 BT_DBG("bad state %1.1x", chan->mode);
1835 err = -EBADFD;
1836 }
1837
1838 return err;
1839}
1840
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841/* Copy frame to all raw sockets on that connection */
1842static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1843{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001845 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846
1847 BT_DBG("conn %p", conn);
1848
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001849 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001850
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001851 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001852 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001853 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 continue;
1855
1856 /* Don't send frame to the socket it came from */
1857 if (skb->sk == sk)
1858 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001859 nskb = skb_clone(skb, GFP_ATOMIC);
1860 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 continue;
1862
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001863 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 kfree_skb(nskb);
1865 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001866
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001867 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001868}
1869
1870/* ---- L2CAP signalling commands ---- */
1871static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1872 u8 code, u8 ident, u16 dlen, void *data)
1873{
1874 struct sk_buff *skb, **frag;
1875 struct l2cap_cmd_hdr *cmd;
1876 struct l2cap_hdr *lh;
1877 int len, count;
1878
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001879 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1880 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881
1882 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1883 count = min_t(unsigned int, conn->mtu, len);
1884
1885 skb = bt_skb_alloc(count, GFP_ATOMIC);
1886 if (!skb)
1887 return NULL;
1888
1889 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001890 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001891
1892 if (conn->hcon->type == LE_LINK)
1893 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1894 else
1895 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896
1897 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1898 cmd->code = code;
1899 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001900 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901
1902 if (dlen) {
1903 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1904 memcpy(skb_put(skb, count), data, count);
1905 data += count;
1906 }
1907
1908 len -= skb->len;
1909
1910 /* Continuation fragments (no L2CAP header) */
1911 frag = &skb_shinfo(skb)->frag_list;
1912 while (len) {
1913 count = min_t(unsigned int, conn->mtu, len);
1914
1915 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1916 if (!*frag)
1917 goto fail;
1918
1919 memcpy(skb_put(*frag, count), data, count);
1920
1921 len -= count;
1922 data += count;
1923
1924 frag = &(*frag)->next;
1925 }
1926
1927 return skb;
1928
1929fail:
1930 kfree_skb(skb);
1931 return NULL;
1932}
1933
1934static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1935{
1936 struct l2cap_conf_opt *opt = *ptr;
1937 int len;
1938
1939 len = L2CAP_CONF_OPT_SIZE + opt->len;
1940 *ptr += len;
1941
1942 *type = opt->type;
1943 *olen = opt->len;
1944
1945 switch (opt->len) {
1946 case 1:
1947 *val = *((u8 *) opt->val);
1948 break;
1949
1950 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001951 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 break;
1953
1954 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001955 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 break;
1957
1958 default:
1959 *val = (unsigned long) opt->val;
1960 break;
1961 }
1962
1963 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1964 return len;
1965}
1966
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1968{
1969 struct l2cap_conf_opt *opt = *ptr;
1970
1971 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1972
1973 opt->type = type;
1974 opt->len = len;
1975
1976 switch (len) {
1977 case 1:
1978 *((u8 *) opt->val) = val;
1979 break;
1980
1981 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001982 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 break;
1984
1985 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001986 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987 break;
1988
1989 default:
1990 memcpy(opt->val, (void *) val, len);
1991 break;
1992 }
1993
1994 *ptr += L2CAP_CONF_OPT_SIZE + len;
1995}
1996
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001997static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1998{
1999 struct l2cap_conf_efs efs;
2000
Szymon Janc1ec918c2011-11-16 09:32:21 +01002001 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002002 case L2CAP_MODE_ERTM:
2003 efs.id = chan->local_id;
2004 efs.stype = chan->local_stype;
2005 efs.msdu = cpu_to_le16(chan->local_msdu);
2006 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2007 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
2008 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
2009 break;
2010
2011 case L2CAP_MODE_STREAMING:
2012 efs.id = 1;
2013 efs.stype = L2CAP_SERV_BESTEFFORT;
2014 efs.msdu = cpu_to_le16(chan->local_msdu);
2015 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2016 efs.acc_lat = 0;
2017 efs.flush_to = 0;
2018 break;
2019
2020 default:
2021 return;
2022 }
2023
2024 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
2025 (unsigned long) &efs);
2026}
2027
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002028static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002029{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002030 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2031 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002032
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02002033 BT_DBG("chan %p", chan);
2034
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002035 l2cap_chan_lock(chan);
2036
Szymon Jancb17e73b2012-01-11 10:59:47 +01002037 __l2cap_send_ack(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002038
2039 l2cap_chan_unlock(chan);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002040
2041 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002042}
2043
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002044static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002045{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002046 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002047 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002048 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002049 chan->num_acked = 0;
2050 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002051
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002052 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2053 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2054 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002055
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002056 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002057
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002058 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002059}
2060
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002061static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2062{
2063 switch (mode) {
2064 case L2CAP_MODE_STREAMING:
2065 case L2CAP_MODE_ERTM:
2066 if (l2cap_mode_supported(mode, remote_feat_mask))
2067 return mode;
2068 /* fall through */
2069 default:
2070 return L2CAP_MODE_BASIC;
2071 }
2072}
2073
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002074static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2075{
2076 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2077}
2078
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002079static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2080{
2081 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2082}
2083
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002084static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2085{
2086 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002087 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002088 /* use extended control field */
2089 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002090 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2091 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002092 chan->tx_win = min_t(u16, chan->tx_win,
2093 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002094 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2095 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002096}
2097
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002098static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002101 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002103 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002105 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002107 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002108 goto done;
2109
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002110 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002111 case L2CAP_MODE_STREAMING:
2112 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002113 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002114 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002115
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002116 if (__l2cap_efs_supported(chan))
2117 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2118
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002119 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002120 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002121 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002122 break;
2123 }
2124
2125done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002126 if (chan->imtu != L2CAP_DEFAULT_MTU)
2127 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002128
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002129 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002130 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002131 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2132 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002133 break;
2134
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002135 rfc.mode = L2CAP_MODE_BASIC;
2136 rfc.txwin_size = 0;
2137 rfc.max_transmit = 0;
2138 rfc.retrans_timeout = 0;
2139 rfc.monitor_timeout = 0;
2140 rfc.max_pdu_size = 0;
2141
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002142 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2143 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002144 break;
2145
2146 case L2CAP_MODE_ERTM:
2147 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002148 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002149 rfc.retrans_timeout = 0;
2150 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002151
2152 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2153 L2CAP_EXT_HDR_SIZE -
2154 L2CAP_SDULEN_SIZE -
2155 L2CAP_FCS_SIZE);
2156 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002157
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002158 l2cap_txwin_setup(chan);
2159
2160 rfc.txwin_size = min_t(u16, chan->tx_win,
2161 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002162
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002163 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2164 (unsigned long) &rfc);
2165
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002166 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2167 l2cap_add_opt_efs(&ptr, chan);
2168
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002169 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002170 break;
2171
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002172 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002173 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002174 chan->fcs = L2CAP_FCS_NONE;
2175 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002176 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002177
2178 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2179 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2180 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002181 break;
2182
2183 case L2CAP_MODE_STREAMING:
2184 rfc.mode = L2CAP_MODE_STREAMING;
2185 rfc.txwin_size = 0;
2186 rfc.max_transmit = 0;
2187 rfc.retrans_timeout = 0;
2188 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002189
2190 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2191 L2CAP_EXT_HDR_SIZE -
2192 L2CAP_SDULEN_SIZE -
2193 L2CAP_FCS_SIZE);
2194 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002195
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002196 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2197 (unsigned long) &rfc);
2198
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002199 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2200 l2cap_add_opt_efs(&ptr, chan);
2201
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002202 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002203 break;
2204
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002205 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002206 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002207 chan->fcs = L2CAP_FCS_NONE;
2208 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002209 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002210 break;
2211 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002213 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002214 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
2216 return ptr - data;
2217}
2218
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002219static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002221 struct l2cap_conf_rsp *rsp = data;
2222 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002223 void *req = chan->conf_req;
2224 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002225 int type, hint, olen;
2226 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002227 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002228 struct l2cap_conf_efs efs;
2229 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002230 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002231 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002232 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002234 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002235
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002236 while (len >= L2CAP_CONF_OPT_SIZE) {
2237 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002239 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002240 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002241
2242 switch (type) {
2243 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002244 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002245 break;
2246
2247 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002248 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002249 break;
2250
2251 case L2CAP_CONF_QOS:
2252 break;
2253
Marcel Holtmann6464f352007-10-20 13:39:51 +02002254 case L2CAP_CONF_RFC:
2255 if (olen == sizeof(rfc))
2256 memcpy(&rfc, (void *) val, olen);
2257 break;
2258
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002259 case L2CAP_CONF_FCS:
2260 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002261 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002262 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002263
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002264 case L2CAP_CONF_EFS:
2265 remote_efs = 1;
2266 if (olen == sizeof(efs))
2267 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002268 break;
2269
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002270 case L2CAP_CONF_EWS:
2271 if (!enable_hs)
2272 return -ECONNREFUSED;
2273
2274 set_bit(FLAG_EXT_CTRL, &chan->flags);
2275 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002276 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002277 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002278 break;
2279
2280 default:
2281 if (hint)
2282 break;
2283
2284 result = L2CAP_CONF_UNKNOWN;
2285 *((u8 *) ptr++) = type;
2286 break;
2287 }
2288 }
2289
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002290 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002291 goto done;
2292
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002293 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002294 case L2CAP_MODE_STREAMING:
2295 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002296 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002297 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002298 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002299 break;
2300 }
2301
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002302 if (remote_efs) {
2303 if (__l2cap_efs_supported(chan))
2304 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2305 else
2306 return -ECONNREFUSED;
2307 }
2308
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002309 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002310 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002311
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002312 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002313 }
2314
2315done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002316 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002317 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002318 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002319
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002320 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002321 return -ECONNREFUSED;
2322
2323 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2324 sizeof(rfc), (unsigned long) &rfc);
2325 }
2326
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002327 if (result == L2CAP_CONF_SUCCESS) {
2328 /* Configure output options and let the other side know
2329 * which ones we don't like. */
2330
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002331 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2332 result = L2CAP_CONF_UNACCEPT;
2333 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002334 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002335 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002336 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002337 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002338
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002339 if (remote_efs) {
2340 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2341 efs.stype != L2CAP_SERV_NOTRAFIC &&
2342 efs.stype != chan->local_stype) {
2343
2344 result = L2CAP_CONF_UNACCEPT;
2345
2346 if (chan->num_conf_req >= 1)
2347 return -ECONNREFUSED;
2348
2349 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002350 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002351 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002352 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002353 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002354 result = L2CAP_CONF_PENDING;
2355 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002356 }
2357 }
2358
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002359 switch (rfc.mode) {
2360 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002361 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002362 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002363 break;
2364
2365 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002366 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2367 chan->remote_tx_win = rfc.txwin_size;
2368 else
2369 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2370
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002371 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002372
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002373 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2374 chan->conn->mtu -
2375 L2CAP_EXT_HDR_SIZE -
2376 L2CAP_SDULEN_SIZE -
2377 L2CAP_FCS_SIZE);
2378 rfc.max_pdu_size = cpu_to_le16(size);
2379 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002380
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002381 rfc.retrans_timeout =
Andrei Emeltchenko4fd21a82012-03-12 12:13:10 +02002382 __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002383 rfc.monitor_timeout =
Andrei Emeltchenko4fd21a82012-03-12 12:13:10 +02002384 __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002385
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002386 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002387
2388 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2389 sizeof(rfc), (unsigned long) &rfc);
2390
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002391 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2392 chan->remote_id = efs.id;
2393 chan->remote_stype = efs.stype;
2394 chan->remote_msdu = le16_to_cpu(efs.msdu);
2395 chan->remote_flush_to =
2396 le32_to_cpu(efs.flush_to);
2397 chan->remote_acc_lat =
2398 le32_to_cpu(efs.acc_lat);
2399 chan->remote_sdu_itime =
2400 le32_to_cpu(efs.sdu_itime);
2401 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2402 sizeof(efs), (unsigned long) &efs);
2403 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002404 break;
2405
2406 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002407 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2408 chan->conn->mtu -
2409 L2CAP_EXT_HDR_SIZE -
2410 L2CAP_SDULEN_SIZE -
2411 L2CAP_FCS_SIZE);
2412 rfc.max_pdu_size = cpu_to_le16(size);
2413 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002414
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002415 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002416
2417 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2418 sizeof(rfc), (unsigned long) &rfc);
2419
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002420 break;
2421
2422 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002423 result = L2CAP_CONF_UNACCEPT;
2424
2425 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002426 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002427 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002428
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002429 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002430 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002431 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002432 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002433 rsp->result = cpu_to_le16(result);
2434 rsp->flags = cpu_to_le16(0x0000);
2435
2436 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437}
2438
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002439static 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 -03002440{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002441 struct l2cap_conf_req *req = data;
2442 void *ptr = req->data;
2443 int type, olen;
2444 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002445 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002446 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002447
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002448 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002449
2450 while (len >= L2CAP_CONF_OPT_SIZE) {
2451 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2452
2453 switch (type) {
2454 case L2CAP_CONF_MTU:
2455 if (val < L2CAP_DEFAULT_MIN_MTU) {
2456 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002457 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002458 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002459 chan->imtu = val;
2460 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002461 break;
2462
2463 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002464 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002465 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002466 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002467 break;
2468
2469 case L2CAP_CONF_RFC:
2470 if (olen == sizeof(rfc))
2471 memcpy(&rfc, (void *)val, olen);
2472
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002473 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002474 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002475 return -ECONNREFUSED;
2476
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002477 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002478
2479 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2480 sizeof(rfc), (unsigned long) &rfc);
2481 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002482
2483 case L2CAP_CONF_EWS:
2484 chan->tx_win = min_t(u16, val,
2485 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002486 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2487 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002488 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002489
2490 case L2CAP_CONF_EFS:
2491 if (olen == sizeof(efs))
2492 memcpy(&efs, (void *)val, olen);
2493
2494 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2495 efs.stype != L2CAP_SERV_NOTRAFIC &&
2496 efs.stype != chan->local_stype)
2497 return -ECONNREFUSED;
2498
2499 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2500 sizeof(efs), (unsigned long) &efs);
2501 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002502 }
2503 }
2504
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002505 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002506 return -ECONNREFUSED;
2507
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002508 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002509
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002510 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002511 switch (rfc.mode) {
2512 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002513 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2514 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2515 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002516
2517 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2518 chan->local_msdu = le16_to_cpu(efs.msdu);
2519 chan->local_sdu_itime =
2520 le32_to_cpu(efs.sdu_itime);
2521 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2522 chan->local_flush_to =
2523 le32_to_cpu(efs.flush_to);
2524 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002525 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002526
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002527 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002528 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002529 }
2530 }
2531
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002532 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002533 req->flags = cpu_to_le16(0x0000);
2534
2535 return ptr - data;
2536}
2537
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002538static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539{
2540 struct l2cap_conf_rsp *rsp = data;
2541 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002543 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002545 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002546 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002547 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002548
2549 return ptr - data;
2550}
2551
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002552void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002553{
2554 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002555 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002556 u8 buf[128];
2557
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002558 rsp.scid = cpu_to_le16(chan->dcid);
2559 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002560 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2561 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2562 l2cap_send_cmd(conn, chan->ident,
2563 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2564
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002565 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002566 return;
2567
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002568 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2569 l2cap_build_conf_req(chan, buf), buf);
2570 chan->num_conf_req++;
2571}
2572
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002573static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002574{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002575 int type, olen;
2576 unsigned long val;
2577 struct l2cap_conf_rfc rfc;
2578
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002579 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002580
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002581 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002582 return;
2583
2584 while (len >= L2CAP_CONF_OPT_SIZE) {
2585 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2586
2587 switch (type) {
2588 case L2CAP_CONF_RFC:
2589 if (olen == sizeof(rfc))
2590 memcpy(&rfc, (void *)val, olen);
2591 goto done;
2592 }
2593 }
2594
Mat Martineau36e999a2011-12-08 17:23:21 -08002595 /* Use sane default values in case a misbehaving remote device
2596 * did not send an RFC option.
2597 */
2598 rfc.mode = chan->mode;
2599 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2600 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2601 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2602
2603 BT_ERR("Expected RFC option was not found, using defaults");
2604
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002605done:
2606 switch (rfc.mode) {
2607 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002608 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2609 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2610 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002611 break;
2612 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002613 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002614 }
2615}
2616
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002617static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2618{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002619 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002620
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002621 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002622 return 0;
2623
2624 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2625 cmd->ident == conn->info_ident) {
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02002626 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002627
2628 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002629 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002630
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002631 l2cap_conn_start(conn);
2632 }
2633
2634 return 0;
2635}
2636
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2638{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2640 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002641 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002642 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002643 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
2645 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002646 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647
Andrei Emeltchenko097db762012-03-09 14:16:17 +02002648 BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
2650 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002651 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2652 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 result = L2CAP_CR_BAD_PSM;
2654 goto sendresp;
2655 }
2656
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002657 parent = pchan->sk;
2658
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002659 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002660 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002661
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002662 /* Check if the ACL is secure enough (if not SDP) */
2663 if (psm != cpu_to_le16(0x0001) &&
2664 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002665 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002666 result = L2CAP_CR_SEC_BLOCK;
2667 goto response;
2668 }
2669
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 result = L2CAP_CR_NO_MEM;
2671
2672 /* Check for backlog size */
2673 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002674 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 goto response;
2676 }
2677
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002678 chan = pchan->ops->new_connection(pchan->data);
2679 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 goto response;
2681
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002682 sk = chan->sk;
2683
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002685 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002687 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 goto response;
2689 }
2690
2691 hci_conn_hold(conn->hcon);
2692
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 bacpy(&bt_sk(sk)->src, conn->src);
2694 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002695 chan->psm = psm;
2696 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002698 bt_accept_enqueue(parent, sk);
2699
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002700 __l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002701
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002702 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002704 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002706 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
Marcel Holtmann984947d2009-02-06 23:35:19 +01002708 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002709 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002710 if (bt_sk(sk)->defer_setup) {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002711 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002712 result = L2CAP_CR_PEND;
2713 status = L2CAP_CS_AUTHOR_PEND;
2714 parent->sk_data_ready(parent, 0);
2715 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002716 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002717 result = L2CAP_CR_SUCCESS;
2718 status = L2CAP_CS_NO_INFO;
2719 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002720 } 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_AUTHEN_PEND;
2724 }
2725 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002726 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002727 result = L2CAP_CR_PEND;
2728 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 }
2730
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002732 release_sock(parent);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002733 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734
2735sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002736 rsp.scid = cpu_to_le16(scid);
2737 rsp.dcid = cpu_to_le16(dcid);
2738 rsp.result = cpu_to_le16(result);
2739 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002741
2742 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2743 struct l2cap_info_req info;
2744 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2745
2746 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2747 conn->info_ident = l2cap_get_ident(conn);
2748
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08002749 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002750
2751 l2cap_send_cmd(conn, conn->info_ident,
2752 L2CAP_INFO_REQ, sizeof(info), &info);
2753 }
2754
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002755 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002756 result == L2CAP_CR_SUCCESS) {
2757 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002758 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002759 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002760 l2cap_build_conf_req(chan, buf), buf);
2761 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002762 }
2763
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 return 0;
2765}
2766
2767static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2768{
2769 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2770 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002771 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 u8 req[128];
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002773 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
2775 scid = __le16_to_cpu(rsp->scid);
2776 dcid = __le16_to_cpu(rsp->dcid);
2777 result = __le16_to_cpu(rsp->result);
2778 status = __le16_to_cpu(rsp->status);
2779
Andrei Emeltchenko1b009c92012-02-21 12:54:54 +02002780 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
2781 dcid, scid, result, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002783 mutex_lock(&conn->chan_lock);
2784
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 if (scid) {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002786 chan = __l2cap_get_chan_by_scid(conn, scid);
2787 if (!chan) {
2788 err = -EFAULT;
2789 goto unlock;
2790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 } else {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002792 chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
2793 if (!chan) {
2794 err = -EFAULT;
2795 goto unlock;
2796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 }
2798
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002799 err = 0;
2800
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002801 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002802
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 switch (result) {
2804 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002805 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002806 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002807 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002808 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002809
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002810 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002811 break;
2812
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002814 l2cap_build_conf_req(chan, req), req);
2815 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 break;
2817
2818 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002819 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820 break;
2821
2822 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002823 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 break;
2825 }
2826
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002827 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002828
2829unlock:
2830 mutex_unlock(&conn->chan_lock);
2831
2832 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833}
2834
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002835static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002836{
2837 /* FCS is enabled only in ERTM or streaming mode, if one or both
2838 * sides request it.
2839 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002840 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002841 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002842 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002843 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002844}
2845
Al Viro88219a02007-07-29 00:17:25 -07002846static 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 -07002847{
2848 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2849 u16 dcid, flags;
2850 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002851 struct l2cap_chan *chan;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002852 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853
2854 dcid = __le16_to_cpu(req->dcid);
2855 flags = __le16_to_cpu(req->flags);
2856
2857 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2858
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002859 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002860 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861 return -ENOENT;
2862
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002863 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002864
David S. Miller033b1142011-07-21 13:38:42 -07002865 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002866 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002867
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002868 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2869 rej.scid = cpu_to_le16(chan->scid);
2870 rej.dcid = cpu_to_le16(chan->dcid);
2871
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002872 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2873 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002874 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002875 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002876
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002877 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002878 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002879 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002880 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002881 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002882 L2CAP_CONF_REJECT, flags), rsp);
2883 goto unlock;
2884 }
2885
2886 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002887 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2888 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889
2890 if (flags & 0x0001) {
2891 /* Incomplete config. Send empty response. */
2892 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002893 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002894 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 goto unlock;
2896 }
2897
2898 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002899 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002900 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002901 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002903 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002905 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002906 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002907
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002908 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002909 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002910
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002911 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002912 goto unlock;
2913
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002914 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002915 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002916
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002917 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002918
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002919 chan->next_tx_seq = 0;
2920 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002921 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002922 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002923 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002924
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02002925 l2cap_chan_ready(chan);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002926 goto unlock;
2927 }
2928
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002929 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002930 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002932 l2cap_build_conf_req(chan, buf), buf);
2933 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 }
2935
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002936 /* Got Conf Rsp PENDING from remote side and asume we sent
2937 Conf Rsp PENDING in the code above */
2938 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2939 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2940
2941 /* check compatibility */
2942
2943 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2944 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2945
2946 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002947 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002948 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2949 }
2950
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951unlock:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002952 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 return 0;
2954}
2955
2956static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2957{
2958 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2959 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002960 struct l2cap_chan *chan;
Andrei Emeltchenko61386cb2012-03-12 12:13:07 +02002961 int len = le16_to_cpu(cmd->len) - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962
2963 scid = __le16_to_cpu(rsp->scid);
2964 flags = __le16_to_cpu(rsp->flags);
2965 result = __le16_to_cpu(rsp->result);
2966
Andrei Emeltchenko61386cb2012-03-12 12:13:07 +02002967 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x len %d", scid, flags,
2968 result, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002970 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002971 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 return 0;
2973
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002974 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002975
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 switch (result) {
2977 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002978 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002979 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 break;
2981
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002982 case L2CAP_CONF_PENDING:
2983 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2984
2985 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2986 char buf[64];
2987
2988 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2989 buf, &result);
2990 if (len < 0) {
2991 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2992 goto done;
2993 }
2994
2995 /* check compatibility */
2996
2997 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2998 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2999
3000 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02003001 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03003002 L2CAP_CONF_SUCCESS, 0x0000), buf);
3003 }
3004 goto done;
3005
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003007 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003008 char req[64];
3009
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003010 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003011 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003012 goto done;
3013 }
3014
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003015 /* throw out any old stored conf requests */
3016 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03003017 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
3018 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003019 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003020 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003021 goto done;
3022 }
3023
3024 l2cap_send_cmd(conn, l2cap_get_ident(conn),
3025 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003026 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003027 if (result != L2CAP_CONF_SUCCESS)
3028 goto done;
3029 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030 }
3031
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09003032 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003033 l2cap_chan_set_err(chan, ECONNRESET);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +02003034
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08003035 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003036 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 goto done;
3038 }
3039
3040 if (flags & 0x01)
3041 goto done;
3042
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003043 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003045 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003046 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003047
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003048 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003049 chan->next_tx_seq = 0;
3050 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003051 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003052 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003053 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003054
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02003055 l2cap_chan_ready(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 }
3057
3058done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003059 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 return 0;
3061}
3062
3063static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3064{
3065 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3066 struct l2cap_disconn_rsp rsp;
3067 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003068 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003069 struct sock *sk;
3070
3071 scid = __le16_to_cpu(req->scid);
3072 dcid = __le16_to_cpu(req->dcid);
3073
3074 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3075
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003076 mutex_lock(&conn->chan_lock);
3077
3078 chan = __l2cap_get_chan_by_scid(conn, dcid);
3079 if (!chan) {
3080 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003084 l2cap_chan_lock(chan);
3085
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003086 sk = chan->sk;
3087
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003088 rsp.dcid = cpu_to_le16(chan->scid);
3089 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3091
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003092 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 sk->sk_shutdown = SHUTDOWN_MASK;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003094 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003096 l2cap_chan_del(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003097
3098 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003100 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003101
3102 mutex_unlock(&conn->chan_lock);
3103
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104 return 0;
3105}
3106
3107static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3108{
3109 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3110 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003111 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112
3113 scid = __le16_to_cpu(rsp->scid);
3114 dcid = __le16_to_cpu(rsp->dcid);
3115
3116 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3117
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003118 mutex_lock(&conn->chan_lock);
3119
3120 chan = __l2cap_get_chan_by_scid(conn, scid);
3121 if (!chan) {
3122 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003124 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003126 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003127
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003128 l2cap_chan_del(chan, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003129
3130 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003132 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003133
3134 mutex_unlock(&conn->chan_lock);
3135
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 return 0;
3137}
3138
3139static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3140{
3141 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 u16 type;
3143
3144 type = __le16_to_cpu(req->type);
3145
3146 BT_DBG("type 0x%4.4x", type);
3147
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003148 if (type == L2CAP_IT_FEAT_MASK) {
3149 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003150 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003151 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3152 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3153 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003154 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003155 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3156 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003157 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003158 feat_mask |= L2CAP_FEAT_EXT_FLOW
3159 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003160
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003161 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003162 l2cap_send_cmd(conn, cmd->ident,
3163 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003164 } else if (type == L2CAP_IT_FIXED_CHAN) {
3165 u8 buf[12];
3166 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003167
3168 if (enable_hs)
3169 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3170 else
3171 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3172
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003173 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3174 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003175 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003176 l2cap_send_cmd(conn, cmd->ident,
3177 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003178 } else {
3179 struct l2cap_info_rsp rsp;
3180 rsp.type = cpu_to_le16(type);
3181 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3182 l2cap_send_cmd(conn, cmd->ident,
3183 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003185
3186 return 0;
3187}
3188
3189static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3190{
3191 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3192 u16 type, result;
3193
3194 type = __le16_to_cpu(rsp->type);
3195 result = __le16_to_cpu(rsp->result);
3196
3197 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3198
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003199 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3200 if (cmd->ident != conn->info_ident ||
3201 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3202 return 0;
3203
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02003204 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003205
Ville Tervoadb08ed2010-08-04 09:43:33 +03003206 if (result != L2CAP_IR_SUCCESS) {
3207 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3208 conn->info_ident = 0;
3209
3210 l2cap_conn_start(conn);
3211
3212 return 0;
3213 }
3214
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003215 switch (type) {
3216 case L2CAP_IT_FEAT_MASK:
Harvey Harrison83985312008-05-02 16:25:46 -07003217 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003218
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003219 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003220 struct l2cap_info_req req;
3221 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3222
3223 conn->info_ident = l2cap_get_ident(conn);
3224
3225 l2cap_send_cmd(conn, conn->info_ident,
3226 L2CAP_INFO_REQ, sizeof(req), &req);
3227 } else {
3228 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3229 conn->info_ident = 0;
3230
3231 l2cap_conn_start(conn);
3232 }
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003233 break;
3234
3235 case L2CAP_IT_FIXED_CHAN:
3236 conn->fixed_chan_mask = rsp->data[0];
Marcel Holtmann984947d2009-02-06 23:35:19 +01003237 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003238 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003239
3240 l2cap_conn_start(conn);
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003241 break;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003242 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003243
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 return 0;
3245}
3246
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003247static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3248 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3249 void *data)
3250{
3251 struct l2cap_create_chan_req *req = data;
3252 struct l2cap_create_chan_rsp rsp;
3253 u16 psm, scid;
3254
3255 if (cmd_len != sizeof(*req))
3256 return -EPROTO;
3257
3258 if (!enable_hs)
3259 return -EINVAL;
3260
3261 psm = le16_to_cpu(req->psm);
3262 scid = le16_to_cpu(req->scid);
3263
3264 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3265
3266 /* Placeholder: Always reject */
3267 rsp.dcid = 0;
3268 rsp.scid = cpu_to_le16(scid);
Andrei Emeltchenko8ce0c492012-03-12 12:13:09 +02003269 rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
3270 rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003271
3272 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3273 sizeof(rsp), &rsp);
3274
3275 return 0;
3276}
3277
3278static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3279 struct l2cap_cmd_hdr *cmd, void *data)
3280{
3281 BT_DBG("conn %p", conn);
3282
3283 return l2cap_connect_rsp(conn, cmd, data);
3284}
3285
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003286static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3287 u16 icid, u16 result)
3288{
3289 struct l2cap_move_chan_rsp rsp;
3290
3291 BT_DBG("icid %d, result %d", icid, result);
3292
3293 rsp.icid = cpu_to_le16(icid);
3294 rsp.result = cpu_to_le16(result);
3295
3296 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3297}
3298
3299static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3300 struct l2cap_chan *chan, u16 icid, u16 result)
3301{
3302 struct l2cap_move_chan_cfm cfm;
3303 u8 ident;
3304
3305 BT_DBG("icid %d, result %d", icid, result);
3306
3307 ident = l2cap_get_ident(conn);
3308 if (chan)
3309 chan->ident = ident;
3310
3311 cfm.icid = cpu_to_le16(icid);
3312 cfm.result = cpu_to_le16(result);
3313
3314 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3315}
3316
3317static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3318 u16 icid)
3319{
3320 struct l2cap_move_chan_cfm_rsp rsp;
3321
3322 BT_DBG("icid %d", icid);
3323
3324 rsp.icid = cpu_to_le16(icid);
3325 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3326}
3327
3328static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3329 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3330{
3331 struct l2cap_move_chan_req *req = data;
3332 u16 icid = 0;
3333 u16 result = L2CAP_MR_NOT_ALLOWED;
3334
3335 if (cmd_len != sizeof(*req))
3336 return -EPROTO;
3337
3338 icid = le16_to_cpu(req->icid);
3339
3340 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3341
3342 if (!enable_hs)
3343 return -EINVAL;
3344
3345 /* Placeholder: Always refuse */
3346 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3347
3348 return 0;
3349}
3350
3351static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3352 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3353{
3354 struct l2cap_move_chan_rsp *rsp = data;
3355 u16 icid, result;
3356
3357 if (cmd_len != sizeof(*rsp))
3358 return -EPROTO;
3359
3360 icid = le16_to_cpu(rsp->icid);
3361 result = le16_to_cpu(rsp->result);
3362
3363 BT_DBG("icid %d, result %d", icid, result);
3364
3365 /* Placeholder: Always unconfirmed */
3366 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3367
3368 return 0;
3369}
3370
3371static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3372 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3373{
3374 struct l2cap_move_chan_cfm *cfm = data;
3375 u16 icid, result;
3376
3377 if (cmd_len != sizeof(*cfm))
3378 return -EPROTO;
3379
3380 icid = le16_to_cpu(cfm->icid);
3381 result = le16_to_cpu(cfm->result);
3382
3383 BT_DBG("icid %d, result %d", icid, result);
3384
3385 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3386
3387 return 0;
3388}
3389
3390static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3391 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3392{
3393 struct l2cap_move_chan_cfm_rsp *rsp = data;
3394 u16 icid;
3395
3396 if (cmd_len != sizeof(*rsp))
3397 return -EPROTO;
3398
3399 icid = le16_to_cpu(rsp->icid);
3400
3401 BT_DBG("icid %d", icid);
3402
3403 return 0;
3404}
3405
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003406static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003407 u16 to_multiplier)
3408{
3409 u16 max_latency;
3410
3411 if (min > max || min < 6 || max > 3200)
3412 return -EINVAL;
3413
3414 if (to_multiplier < 10 || to_multiplier > 3200)
3415 return -EINVAL;
3416
3417 if (max >= to_multiplier * 8)
3418 return -EINVAL;
3419
3420 max_latency = (to_multiplier * 8 / max) - 1;
3421 if (latency > 499 || latency > max_latency)
3422 return -EINVAL;
3423
3424 return 0;
3425}
3426
3427static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3428 struct l2cap_cmd_hdr *cmd, u8 *data)
3429{
3430 struct hci_conn *hcon = conn->hcon;
3431 struct l2cap_conn_param_update_req *req;
3432 struct l2cap_conn_param_update_rsp rsp;
3433 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003434 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003435
3436 if (!(hcon->link_mode & HCI_LM_MASTER))
3437 return -EINVAL;
3438
3439 cmd_len = __le16_to_cpu(cmd->len);
3440 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3441 return -EPROTO;
3442
3443 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003444 min = __le16_to_cpu(req->min);
3445 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003446 latency = __le16_to_cpu(req->latency);
3447 to_multiplier = __le16_to_cpu(req->to_multiplier);
3448
3449 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3450 min, max, latency, to_multiplier);
3451
3452 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003453
3454 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3455 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003456 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3457 else
3458 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3459
3460 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3461 sizeof(rsp), &rsp);
3462
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003463 if (!err)
3464 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3465
Claudio Takahaside731152011-02-11 19:28:55 -02003466 return 0;
3467}
3468
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003469static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3470 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3471{
3472 int err = 0;
3473
3474 switch (cmd->code) {
3475 case L2CAP_COMMAND_REJ:
3476 l2cap_command_rej(conn, cmd, data);
3477 break;
3478
3479 case L2CAP_CONN_REQ:
3480 err = l2cap_connect_req(conn, cmd, data);
3481 break;
3482
3483 case L2CAP_CONN_RSP:
3484 err = l2cap_connect_rsp(conn, cmd, data);
3485 break;
3486
3487 case L2CAP_CONF_REQ:
3488 err = l2cap_config_req(conn, cmd, cmd_len, data);
3489 break;
3490
3491 case L2CAP_CONF_RSP:
3492 err = l2cap_config_rsp(conn, cmd, data);
3493 break;
3494
3495 case L2CAP_DISCONN_REQ:
3496 err = l2cap_disconnect_req(conn, cmd, data);
3497 break;
3498
3499 case L2CAP_DISCONN_RSP:
3500 err = l2cap_disconnect_rsp(conn, cmd, data);
3501 break;
3502
3503 case L2CAP_ECHO_REQ:
3504 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3505 break;
3506
3507 case L2CAP_ECHO_RSP:
3508 break;
3509
3510 case L2CAP_INFO_REQ:
3511 err = l2cap_information_req(conn, cmd, data);
3512 break;
3513
3514 case L2CAP_INFO_RSP:
3515 err = l2cap_information_rsp(conn, cmd, data);
3516 break;
3517
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003518 case L2CAP_CREATE_CHAN_REQ:
3519 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3520 break;
3521
3522 case L2CAP_CREATE_CHAN_RSP:
3523 err = l2cap_create_channel_rsp(conn, cmd, data);
3524 break;
3525
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003526 case L2CAP_MOVE_CHAN_REQ:
3527 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3528 break;
3529
3530 case L2CAP_MOVE_CHAN_RSP:
3531 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3532 break;
3533
3534 case L2CAP_MOVE_CHAN_CFM:
3535 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3536 break;
3537
3538 case L2CAP_MOVE_CHAN_CFM_RSP:
3539 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3540 break;
3541
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003542 default:
3543 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3544 err = -EINVAL;
3545 break;
3546 }
3547
3548 return err;
3549}
3550
3551static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3552 struct l2cap_cmd_hdr *cmd, u8 *data)
3553{
3554 switch (cmd->code) {
3555 case L2CAP_COMMAND_REJ:
3556 return 0;
3557
3558 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003559 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003560
3561 case L2CAP_CONN_PARAM_UPDATE_RSP:
3562 return 0;
3563
3564 default:
3565 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3566 return -EINVAL;
3567 }
3568}
3569
3570static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3571 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572{
3573 u8 *data = skb->data;
3574 int len = skb->len;
3575 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003576 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577
3578 l2cap_raw_recv(conn, skb);
3579
3580 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003581 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3583 data += L2CAP_CMD_HDR_SIZE;
3584 len -= L2CAP_CMD_HDR_SIZE;
3585
Al Viro88219a02007-07-29 00:17:25 -07003586 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587
Al Viro88219a02007-07-29 00:17:25 -07003588 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 -07003589
Al Viro88219a02007-07-29 00:17:25 -07003590 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 BT_DBG("corrupted command");
3592 break;
3593 }
3594
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003595 if (conn->hcon->type == LE_LINK)
3596 err = l2cap_le_sig_cmd(conn, &cmd, data);
3597 else
3598 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599
3600 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003601 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003602
3603 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604
3605 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003606 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3608 }
3609
Al Viro88219a02007-07-29 00:17:25 -07003610 data += cmd_len;
3611 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612 }
3613
3614 kfree_skb(skb);
3615}
3616
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003617static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003618{
3619 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003620 int hdr_size;
3621
3622 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3623 hdr_size = L2CAP_EXT_HDR_SIZE;
3624 else
3625 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003626
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003627 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003628 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003629 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3630 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3631
3632 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003633 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003634 }
3635 return 0;
3636}
3637
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003638static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003639{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003640 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003641
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003642 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003643
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003644 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003645
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003646 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003647 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003648 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003649 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003650 }
3651
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003652 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003653 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003654
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003655 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003656
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003657 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003658 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003659 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003660 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003661 }
3662}
3663
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003664static 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 -03003665{
3666 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003667 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003668
3669 bt_cb(skb)->tx_seq = tx_seq;
3670 bt_cb(skb)->sar = sar;
3671
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003672 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003673
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003674 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003675
Szymon Janc039d9572011-11-16 09:32:19 +01003676 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003677 if (bt_cb(next_skb)->tx_seq == tx_seq)
3678 return -EINVAL;
3679
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003680 next_tx_seq_offset = __seq_offset(chan,
3681 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003682
3683 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003684 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003685 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003686 }
3687
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003688 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003689 next_skb = NULL;
3690 else
3691 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3692 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003693
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003694 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003695
3696 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003697}
3698
Mat Martineau84084a32011-07-22 14:54:00 -07003699static void append_skb_frag(struct sk_buff *skb,
3700 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003701{
Mat Martineau84084a32011-07-22 14:54:00 -07003702 /* skb->len reflects data in skb as well as all fragments
3703 * skb->data_len reflects only data in fragments
3704 */
3705 if (!skb_has_frag_list(skb))
3706 skb_shinfo(skb)->frag_list = new_frag;
3707
3708 new_frag->next = NULL;
3709
3710 (*last_frag)->next = new_frag;
3711 *last_frag = new_frag;
3712
3713 skb->len += new_frag->len;
3714 skb->data_len += new_frag->len;
3715 skb->truesize += new_frag->truesize;
3716}
3717
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003718static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003719{
3720 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003721
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003722 switch (__get_ctrl_sar(chan, control)) {
3723 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003724 if (chan->sdu)
3725 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003726
Mat Martineau84084a32011-07-22 14:54:00 -07003727 err = chan->ops->recv(chan->data, skb);
3728 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003729
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003730 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003731 if (chan->sdu)
3732 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003733
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003734 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003735 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003736
Mat Martineau84084a32011-07-22 14:54:00 -07003737 if (chan->sdu_len > chan->imtu) {
3738 err = -EMSGSIZE;
3739 break;
3740 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003741
Mat Martineau84084a32011-07-22 14:54:00 -07003742 if (skb->len >= chan->sdu_len)
3743 break;
3744
3745 chan->sdu = skb;
3746 chan->sdu_last_frag = skb;
3747
3748 skb = NULL;
3749 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003750 break;
3751
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003752 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003753 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003754 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003755
Mat Martineau84084a32011-07-22 14:54:00 -07003756 append_skb_frag(chan->sdu, skb,
3757 &chan->sdu_last_frag);
3758 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003759
Mat Martineau84084a32011-07-22 14:54:00 -07003760 if (chan->sdu->len >= chan->sdu_len)
3761 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003762
Mat Martineau84084a32011-07-22 14:54:00 -07003763 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003764 break;
3765
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003766 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003767 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003768 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003769
Mat Martineau84084a32011-07-22 14:54:00 -07003770 append_skb_frag(chan->sdu, skb,
3771 &chan->sdu_last_frag);
3772 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003773
Mat Martineau84084a32011-07-22 14:54:00 -07003774 if (chan->sdu->len != chan->sdu_len)
3775 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003776
Mat Martineau84084a32011-07-22 14:54:00 -07003777 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003778
Mat Martineau84084a32011-07-22 14:54:00 -07003779 if (!err) {
3780 /* Reassembly complete */
3781 chan->sdu = NULL;
3782 chan->sdu_last_frag = NULL;
3783 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003784 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003785 break;
3786 }
3787
Mat Martineau84084a32011-07-22 14:54:00 -07003788 if (err) {
3789 kfree_skb(skb);
3790 kfree_skb(chan->sdu);
3791 chan->sdu = NULL;
3792 chan->sdu_last_frag = NULL;
3793 chan->sdu_len = 0;
3794 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003795
Mat Martineau84084a32011-07-22 14:54:00 -07003796 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003797}
3798
Mat Martineau26f880d2011-07-07 09:39:01 -07003799static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003800{
Mat Martineau26f880d2011-07-07 09:39:01 -07003801 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003802
Mat Martineau26f880d2011-07-07 09:39:01 -07003803 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3804
Szymon Janc77f918b2012-01-11 10:59:48 +01003805 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003806}
3807
3808static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3809{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003810 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003811
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003812 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003813 goto done;
3814
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003815 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003816 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003817 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003818 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003819 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003820
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003821 __clear_retrans_timer(chan);
3822 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003823
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003824 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003825
3826done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003827 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3828 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003829
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003830 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003831}
3832
Mat Martineaue3281402011-07-07 09:39:02 -07003833void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003834{
Mat Martineaue3281402011-07-07 09:39:02 -07003835 if (chan->mode == L2CAP_MODE_ERTM) {
3836 if (busy)
3837 l2cap_ertm_enter_local_busy(chan);
3838 else
3839 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003840 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003841}
3842
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003843static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003844{
3845 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003846 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003847
Mat Martineaue3281402011-07-07 09:39:02 -07003848 while ((skb = skb_peek(&chan->srej_q)) &&
3849 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3850 int err;
3851
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003852 if (bt_cb(skb)->tx_seq != tx_seq)
3853 break;
3854
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003855 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003856 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003857 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003858
3859 if (err < 0) {
3860 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3861 break;
3862 }
3863
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003864 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3865 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003866 }
3867}
3868
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003869static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003870{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003871 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003872 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003873
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003874 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003875 if (l->tx_seq == tx_seq) {
3876 list_del(&l->list);
3877 kfree(l);
3878 return;
3879 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003880 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003881 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003882 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003883 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003884 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003885 }
3886}
3887
Szymon Jancaef89f22011-11-16 09:32:18 +01003888static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003889{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003890 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003891 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003892
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003893 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003894 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003895 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003896 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003897
3898 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003899 if (!new)
3900 return -ENOMEM;
3901
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003902 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003903
3904 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3905
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003906 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003907 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003908
3909 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003910
3911 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003912}
3913
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003914static 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 -03003915{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003916 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003917 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003918 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003919 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003920 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003921 int err = 0;
3922
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003923 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 -03003924 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003925
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003926 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003927 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003928 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003929 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003930 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003931 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003932 }
3933
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003934 chan->expected_ack_seq = req_seq;
3935 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003936
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003937 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003938
3939 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003940 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003941 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003942 goto drop;
3943 }
3944
Szymon Janc77f918b2012-01-11 10:59:48 +01003945 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3946 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3947 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003948 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003949 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003950
Mat Martineau02f1b642011-06-29 14:35:19 -07003951 if (tx_seq == chan->expected_tx_seq)
3952 goto expected;
3953
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003954 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003955 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003956
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003957 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003958 struct srej_list, list);
3959 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003960 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003961 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003962
3963 list_del(&first->list);
3964 kfree(first);
3965
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003966 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003967 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003968 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003969 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003970 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003971 }
3972 } else {
3973 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003974
3975 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003976 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003977 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003978
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003979 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003980 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003981 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003982 return 0;
3983 }
3984 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003985
3986 err = l2cap_send_srejframe(chan, tx_seq);
3987 if (err < 0) {
3988 l2cap_send_disconn_req(chan->conn, chan, -err);
3989 return err;
3990 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003991 }
3992 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003993 expected_tx_seq_offset = __seq_offset(chan,
3994 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003995
3996 /* duplicated tx_seq */
3997 if (tx_seq_offset < expected_tx_seq_offset)
3998 goto drop;
3999
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004000 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004001
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004002 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004003
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03004004 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004005 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004006
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004007 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004008 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004009
Szymon Janc0ef3ef02012-01-11 10:59:46 +01004010 /* Set P-bit only if there are some I-frames to ack. */
4011 if (__clear_ack_timer(chan))
4012 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03004013
Szymon Jancaef89f22011-11-16 09:32:18 +01004014 err = l2cap_send_srejframe(chan, tx_seq);
4015 if (err < 0) {
4016 l2cap_send_disconn_req(chan->conn, chan, -err);
4017 return err;
4018 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004019 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004020 return 0;
4021
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004022expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004023 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004024
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004025 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03004026 bt_cb(skb)->tx_seq = tx_seq;
4027 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004028 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004029 return 0;
4030 }
4031
Mat Martineau84084a32011-07-22 14:54:00 -07004032 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004033 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4034
Mat Martineaue3281402011-07-07 09:39:02 -07004035 if (err < 0) {
4036 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4037 return err;
4038 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03004039
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004040 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004041 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004042 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03004043 }
4044
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03004045
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004046 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
4047 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004048 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03004049 else
4050 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03004051
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004052 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03004053
4054drop:
4055 kfree_skb(skb);
4056 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004057}
4058
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004059static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004060{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004061 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004062 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004063
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004064 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004065 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004066
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004067 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004068 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4069 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4070 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004071 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004072 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004073
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004074 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004075 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004076 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004077 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004078 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004079
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004080 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004081 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004082
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004083 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004084 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004085
4086 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004087 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004088 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004089 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004090
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004091 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4092 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004093 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004094 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004095 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004096 }
4097}
4098
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004099static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004100{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004101 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004102
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004103 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004104
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004105 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004106
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004107 chan->expected_ack_seq = tx_seq;
4108 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004109
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004110 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004111 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004112 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004113 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004114 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004115
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004116 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4117 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004118 }
4119}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004120static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004121{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004122 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004123
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004124 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004125
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004126 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004127
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004128 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004129 chan->expected_ack_seq = tx_seq;
4130 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004131
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004132 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004133 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004134
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004135 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004136
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004137 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004138 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004139 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004140 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004141 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004142 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004143 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004144 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004145 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004146 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004147 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004148 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004149 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004150 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004151 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004152 }
4153 }
4154}
4155
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004156static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004157{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004158 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004159
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004160 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004161
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004162 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004163 chan->expected_ack_seq = tx_seq;
4164 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004165
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004166 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004167 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004168
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004169 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004170 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004171 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004172 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004173 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004174 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004175
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004176 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004177 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004178 } else {
4179 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4180 l2cap_send_sframe(chan, rx_control);
4181 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004182}
4183
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004184static 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 -03004185{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004186 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004187
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004188 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004189 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004190 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004191 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004192 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004193 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004194 }
4195
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004196 switch (__get_ctrl_super(chan, rx_control)) {
4197 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004198 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004199 break;
4200
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004201 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004202 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004203 break;
4204
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004205 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004206 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004207 break;
4208
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004209 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004210 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004211 break;
4212 }
4213
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004214 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004215 return 0;
4216}
4217
Szymon Janccad8f1d02012-01-23 10:06:05 +01004218static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004219{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004220 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004221 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004222 int len, next_tx_seq_offset, req_seq_offset;
4223
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004224 control = __get_control(chan, skb->data);
4225 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004226 len = skb->len;
4227
4228 /*
4229 * We can just drop the corrupted I-frame here.
4230 * Receiver will miss it and start proper recovery
4231 * procedures and ask retransmission.
4232 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004233 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004234 goto drop;
4235
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004236 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004237 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004238
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004239 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004240 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004241
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004242 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004243 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004244 goto drop;
4245 }
4246
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004247 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004248
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004249 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4250
4251 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4252 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004253
4254 /* check for invalid req-seq */
4255 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004256 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004257 goto drop;
4258 }
4259
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004260 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004261 if (len < 0) {
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_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004267 } else {
4268 if (len != 0) {
4269 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004270 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004271 goto drop;
4272 }
4273
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004274 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004275 }
4276
4277 return 0;
4278
4279drop:
4280 kfree_skb(skb);
4281 return 0;
4282}
4283
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4285{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004286 struct l2cap_chan *chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004287 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004288 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004289 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004291 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004292 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293 BT_DBG("unknown cid 0x%4.4x", cid);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004294 /* Drop packet and return */
Dan Carpenter33790132012-02-28 09:52:46 +03004295 kfree_skb(skb);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004296 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 }
4298
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004299 l2cap_chan_lock(chan);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004300
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004301 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004303 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 goto drop;
4305
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004306 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004307 case L2CAP_MODE_BASIC:
4308 /* If socket recv buffers overflows we drop data here
4309 * which is *bad* because L2CAP has to be reliable.
4310 * But we don't have any other choice. L2CAP doesn't
4311 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004313 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004314 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004316 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004317 goto done;
4318 break;
4319
4320 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004321 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004322
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004323 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004324
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004325 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004326 control = __get_control(chan, skb->data);
4327 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004328 len = skb->len;
4329
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004330 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004331 goto drop;
4332
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004333 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004334 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004335
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004336 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004337 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004338
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004339 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004340 goto drop;
4341
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004342 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004343
Mat Martineau84084a32011-07-22 14:54:00 -07004344 if (chan->expected_tx_seq != tx_seq) {
4345 /* Frame(s) missing - must discard partial SDU */
4346 kfree_skb(chan->sdu);
4347 chan->sdu = NULL;
4348 chan->sdu_last_frag = NULL;
4349 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004350
Mat Martineau84084a32011-07-22 14:54:00 -07004351 /* TODO: Notify userland of missing data */
4352 }
4353
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004354 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004355
4356 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4357 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004358
4359 goto done;
4360
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004361 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004362 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004363 break;
4364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365
4366drop:
4367 kfree_skb(skb);
4368
4369done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004370 l2cap_chan_unlock(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +02004371
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372 return 0;
4373}
4374
Al Viro8e036fc2007-07-29 00:16:36 -07004375static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004377 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004379 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4380 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 goto drop;
4382
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004383 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004385 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 goto drop;
4387
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004388 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 goto drop;
4390
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004391 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004392 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393
4394drop:
4395 kfree_skb(skb);
4396
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 return 0;
4398}
4399
Andrei Emeltchenkod9b88702012-03-12 12:13:08 +02004400static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
4401 struct sk_buff *skb)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004402{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004403 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004404
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004405 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4406 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004407 goto drop;
4408
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004409 BT_DBG("chan %p, len %d", chan, skb->len);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004410
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004411 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004412 goto drop;
4413
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004414 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004415 goto drop;
4416
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004417 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004418 return 0;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004419
4420drop:
4421 kfree_skb(skb);
4422
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004423 return 0;
4424}
4425
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4427{
4428 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004429 u16 cid, len;
4430 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431
4432 skb_pull(skb, L2CAP_HDR_SIZE);
4433 cid = __le16_to_cpu(lh->cid);
4434 len = __le16_to_cpu(lh->len);
4435
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004436 if (len != skb->len) {
4437 kfree_skb(skb);
4438 return;
4439 }
4440
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4442
4443 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004444 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004445 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 l2cap_sig_channel(conn, skb);
4447 break;
4448
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004449 case L2CAP_CID_CONN_LESS:
Andrei Emeltchenko097db762012-03-09 14:16:17 +02004450 psm = get_unaligned((__le16 *) skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451 skb_pull(skb, 2);
4452 l2cap_conless_channel(conn, psm, skb);
4453 break;
4454
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004455 case L2CAP_CID_LE_DATA:
4456 l2cap_att_channel(conn, cid, skb);
4457 break;
4458
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004459 case L2CAP_CID_SMP:
4460 if (smp_sig_channel(conn, skb))
4461 l2cap_conn_del(conn->hcon, EACCES);
4462 break;
4463
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464 default:
4465 l2cap_data_channel(conn, cid, skb);
4466 break;
4467 }
4468}
4469
4470/* ---- L2CAP interface with lower layer (HCI) ---- */
4471
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004472int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473{
4474 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004475 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4478
4479 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004480 read_lock(&chan_list_lock);
4481 list_for_each_entry(c, &chan_list, global_l) {
4482 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004483
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004484 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 continue;
4486
4487 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004488 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004489 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004490 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004492 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4493 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004494 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004495 lm2 |= HCI_LM_MASTER;
4496 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004498 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499
4500 return exact ? lm1 : lm2;
4501}
4502
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004503int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504{
Marcel Holtmann01394182006-07-03 10:02:46 +02004505 struct l2cap_conn *conn;
4506
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4508
Linus Torvalds1da177e2005-04-16 15:20:36 -07004509 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 conn = l2cap_conn_add(hcon, status);
4511 if (conn)
4512 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004513 } else
Joe Perchese1750722011-06-29 18:18:29 -07004514 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515
4516 return 0;
4517}
4518
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004519int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004520{
4521 struct l2cap_conn *conn = hcon->l2cap_data;
4522
4523 BT_DBG("hcon %p", hcon);
4524
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004525 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004526 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004527 return conn->disc_reason;
4528}
4529
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004530int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531{
4532 BT_DBG("hcon %p reason %d", hcon, reason);
4533
Joe Perchese1750722011-06-29 18:18:29 -07004534 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535 return 0;
4536}
4537
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004538static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004539{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004540 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004541 return;
4542
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004543 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004544 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004545 __clear_chan_timer(chan);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004546 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004547 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004548 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004549 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004550 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004551 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004552 }
4553}
4554
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004555int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004557 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004558 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559
Marcel Holtmann01394182006-07-03 10:02:46 +02004560 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004562
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 BT_DBG("conn %p", conn);
4564
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004565 if (hcon->type == LE_LINK) {
4566 smp_distribute_keys(conn, 0);
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02004567 cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004568 }
4569
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004570 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004572 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004573 l2cap_chan_lock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004575 BT_DBG("chan->scid %d", chan->scid);
4576
4577 if (chan->scid == L2CAP_CID_LE_DATA) {
4578 if (!status && encrypt) {
4579 chan->sec_level = hcon->sec_level;
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02004580 l2cap_chan_ready(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004581 }
4582
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004583 l2cap_chan_unlock(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004584 continue;
4585 }
4586
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004587 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004588 l2cap_chan_unlock(chan);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004589 continue;
4590 }
4591
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004592 if (!status && (chan->state == BT_CONNECTED ||
4593 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004594 l2cap_check_encryption(chan, encrypt);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004595 l2cap_chan_unlock(chan);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004596 continue;
4597 }
4598
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004599 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004600 if (!status) {
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +02004601 l2cap_send_conn_req(chan);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004602 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004603 __clear_chan_timer(chan);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004604 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004605 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004606 } else if (chan->state == BT_CONNECT2) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004607 struct sock *sk = chan->sk;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004608 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004609 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004610
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004611 lock_sock(sk);
4612
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004613 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004614 if (bt_sk(sk)->defer_setup) {
4615 struct sock *parent = bt_sk(sk)->parent;
4616 res = L2CAP_CR_PEND;
4617 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004618 if (parent)
4619 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004620 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004621 __l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004622 res = L2CAP_CR_SUCCESS;
4623 stat = L2CAP_CS_NO_INFO;
4624 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004625 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004626 __l2cap_state_change(chan, BT_DISCONN);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004627 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004628 res = L2CAP_CR_SEC_BLOCK;
4629 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004630 }
4631
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004632 release_sock(sk);
4633
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004634 rsp.scid = cpu_to_le16(chan->dcid);
4635 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004636 rsp.result = cpu_to_le16(res);
4637 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004638 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4639 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 }
4641
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004642 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 }
4644
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004645 mutex_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004646
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 return 0;
4648}
4649
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004650int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651{
4652 struct l2cap_conn *conn = hcon->l2cap_data;
4653
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004654 if (!conn)
4655 conn = l2cap_conn_add(hcon, 0);
4656
4657 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 goto drop;
4659
4660 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4661
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004662 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004663 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004664 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004665 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 int len;
4667
4668 if (conn->rx_len) {
4669 BT_ERR("Unexpected start frame (len %d)", skb->len);
4670 kfree_skb(conn->rx_skb);
4671 conn->rx_skb = NULL;
4672 conn->rx_len = 0;
4673 l2cap_conn_unreliable(conn, ECOMM);
4674 }
4675
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004676 /* Start fragment always begin with Basic L2CAP header */
4677 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 BT_ERR("Frame is too short (len %d)", skb->len);
4679 l2cap_conn_unreliable(conn, ECOMM);
4680 goto drop;
4681 }
4682
4683 hdr = (struct l2cap_hdr *) skb->data;
4684 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004685 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004686
4687 if (len == skb->len) {
4688 /* Complete frame received */
4689 l2cap_recv_frame(conn, skb);
4690 return 0;
4691 }
4692
4693 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4694
4695 if (skb->len > len) {
4696 BT_ERR("Frame is too long (len %d, expected len %d)",
4697 skb->len, len);
4698 l2cap_conn_unreliable(conn, ECOMM);
4699 goto drop;
4700 }
4701
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004702 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004703
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004704 if (chan && chan->sk) {
4705 struct sock *sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004706 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004707
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004708 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004709 BT_ERR("Frame exceeding recv MTU (len %d, "
4710 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004711 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004712 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004713 l2cap_conn_unreliable(conn, ECOMM);
4714 goto drop;
4715 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004716 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004717 }
4718
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004720 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4721 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 goto drop;
4723
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004724 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004725 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 conn->rx_len = len - skb->len;
4727 } else {
4728 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4729
4730 if (!conn->rx_len) {
4731 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4732 l2cap_conn_unreliable(conn, ECOMM);
4733 goto drop;
4734 }
4735
4736 if (skb->len > conn->rx_len) {
4737 BT_ERR("Fragment is too long (len %d, expected %d)",
4738 skb->len, conn->rx_len);
4739 kfree_skb(conn->rx_skb);
4740 conn->rx_skb = NULL;
4741 conn->rx_len = 0;
4742 l2cap_conn_unreliable(conn, ECOMM);
4743 goto drop;
4744 }
4745
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004746 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004747 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 conn->rx_len -= skb->len;
4749
4750 if (!conn->rx_len) {
4751 /* Complete frame received */
4752 l2cap_recv_frame(conn, conn->rx_skb);
4753 conn->rx_skb = NULL;
4754 }
4755 }
4756
4757drop:
4758 kfree_skb(skb);
4759 return 0;
4760}
4761
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004762static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004764 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004766 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004768 list_for_each_entry(c, &chan_list, global_l) {
4769 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004771 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 +01004772 batostr(&bt_sk(sk)->src),
4773 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004774 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004775 c->scid, c->dcid, c->imtu, c->omtu,
4776 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004779 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004780
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004781 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782}
4783
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004784static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4785{
4786 return single_open(file, l2cap_debugfs_show, inode->i_private);
4787}
4788
4789static const struct file_operations l2cap_debugfs_fops = {
4790 .open = l2cap_debugfs_open,
4791 .read = seq_read,
4792 .llseek = seq_lseek,
4793 .release = single_release,
4794};
4795
4796static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004798int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799{
4800 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004801
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004802 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004803 if (err < 0)
4804 return err;
4805
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004806 if (bt_debugfs) {
4807 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4808 bt_debugfs, NULL, &l2cap_debugfs_fops);
4809 if (!l2cap_debugfs)
4810 BT_ERR("Failed to create L2CAP debug file");
4811 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814}
4815
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004816void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004817{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004818 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004819 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004820}
4821
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004822module_param(disable_ertm, bool, 0644);
4823MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");