blob: 94552b33d528447eea4b604b996c7d90ba0ab036 [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. Padovan710f9b0a2011-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,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300304 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 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300836static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300837{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300838 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300839
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300840 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300841
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300842 list_for_each_entry(c, &chan_list, global_l) {
843 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300844
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300845 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300846 continue;
847
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300848 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300849 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300850 if (!bacmp(&bt_sk(sk)->src, src)) {
851 read_unlock(&chan_list_lock);
852 return c;
853 }
Ville Tervob62f3282011-02-10 22:38:50 -0300854
855 /* Closest match */
856 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300857 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300858 }
859 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300860
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300861 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300862
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300863 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300864}
865
866static void l2cap_le_conn_ready(struct l2cap_conn *conn)
867{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300868 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300869 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300870
871 BT_DBG("");
872
873 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300874 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300875 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300876 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300877 return;
878
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300879 parent = pchan->sk;
880
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300881 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300882
Ville Tervob62f3282011-02-10 22:38:50 -0300883 /* Check for backlog size */
884 if (sk_acceptq_is_full(parent)) {
885 BT_DBG("backlog full %d", parent->sk_ack_backlog);
886 goto clean;
887 }
888
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300889 chan = pchan->ops->new_connection(pchan->data);
890 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300891 goto clean;
892
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300893 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300894
Ville Tervob62f3282011-02-10 22:38:50 -0300895 hci_conn_hold(conn->hcon);
896
Ville Tervob62f3282011-02-10 22:38:50 -0300897 bacpy(&bt_sk(sk)->src, conn->src);
898 bacpy(&bt_sk(sk)->dst, conn->dst);
899
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300900 bt_accept_enqueue(parent, sk);
901
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200902 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300903
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300904 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300905
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200906 __l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300907 parent->sk_data_ready(parent, 0);
908
Ville Tervob62f3282011-02-10 22:38:50 -0300909clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300910 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300911}
912
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200913static void l2cap_chan_ready(struct l2cap_chan *chan)
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300914{
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200915 struct sock *sk = chan->sk;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200916 struct sock *parent;
917
918 lock_sock(sk);
919
920 parent = bt_sk(sk)->parent;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300921
922 BT_DBG("sk %p, parent %p", sk, parent);
923
924 chan->conf_state = 0;
925 __clear_chan_timer(chan);
926
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200927 __l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300928 sk->sk_state_change(sk);
929
930 if (parent)
931 parent->sk_data_ready(parent, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200932
933 release_sock(sk);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300934}
935
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200936static void l2cap_conn_ready(struct l2cap_conn *conn)
937{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300938 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200939
940 BT_DBG("conn %p", conn);
941
Ville Tervob62f3282011-02-10 22:38:50 -0300942 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
943 l2cap_le_conn_ready(conn);
944
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300945 if (conn->hcon->out && conn->hcon->type == LE_LINK)
946 smp_conn_security(conn, conn->hcon->pending_sec_level);
947
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200948 mutex_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200949
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200950 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300951
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200952 l2cap_chan_lock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200953
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300954 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300955 if (smp_conn_security(conn, chan->sec_level))
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200956 l2cap_chan_ready(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300957
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300958 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200959 struct sock *sk = chan->sk;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300960 __clear_chan_timer(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200961 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200962 __l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200963 sk->sk_state_change(sk);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200964 release_sock(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300965
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300966 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300967 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200968
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200969 l2cap_chan_unlock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200970 }
971
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200972 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200973}
974
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200975/* Notify sockets that we cannot guaranty reliability anymore */
976static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
977{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300978 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200979
980 BT_DBG("conn %p", conn);
981
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200982 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200983
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200984 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300985 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200986 __l2cap_chan_set_err(chan, err);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200987 }
988
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200989 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200990}
991
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200992static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200993{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200994 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200995 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200996
Marcel Holtmann984947d2009-02-06 23:35:19 +0100997 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100998 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100999
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001000 l2cap_conn_start(conn);
1001}
1002
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001003static void l2cap_conn_del(struct hci_conn *hcon, int err)
1004{
1005 struct l2cap_conn *conn = hcon->l2cap_data;
1006 struct l2cap_chan *chan, *l;
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001007
1008 if (!conn)
1009 return;
1010
1011 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1012
1013 kfree_skb(conn->rx_skb);
1014
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001015 mutex_lock(&conn->chan_lock);
1016
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001017 /* Kill channels */
1018 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001019 l2cap_chan_lock(chan);
1020
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001021 l2cap_chan_del(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001022
1023 l2cap_chan_unlock(chan);
1024
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001025 chan->ops->close(chan->data);
1026 }
1027
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001028 mutex_unlock(&conn->chan_lock);
1029
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001030 hci_chan_del(conn->hchan);
1031
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001032 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim127074b2012-01-30 18:26:29 -02001033 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001034
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001035 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim127074b2012-01-30 18:26:29 -02001036 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001037 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001038 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001039
1040 hcon->l2cap_data = NULL;
1041 kfree(conn);
1042}
1043
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001044static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001045{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001046 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1047 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001048
1049 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1050}
1051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1053{
Marcel Holtmann01394182006-07-03 10:02:46 +02001054 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001055 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
Marcel Holtmann01394182006-07-03 10:02:46 +02001057 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 return conn;
1059
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001060 hchan = hci_chan_create(hcon);
1061 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001064 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1065 if (!conn) {
1066 hci_chan_del(hchan);
1067 return NULL;
1068 }
1069
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 hcon->l2cap_data = conn;
1071 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001072 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001074 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001075
Ville Tervoacd7d372011-02-10 22:38:49 -03001076 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1077 conn->mtu = hcon->hdev->le_mtu;
1078 else
1079 conn->mtu = hcon->hdev->acl_mtu;
1080
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 conn->src = &hcon->hdev->bdaddr;
1082 conn->dst = &hcon->dst;
1083
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001084 conn->feat_mask = 0;
1085
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 spin_lock_init(&conn->lock);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001087 mutex_init(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001088
1089 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001091 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001092 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001093 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001094 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001095
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001096 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001097
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 return conn;
1099}
1100
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103/* Find socket with psm and source bdaddr.
1104 * Returns closest match.
1105 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001106static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001108 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001110 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001111
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001112 list_for_each_entry(c, &chan_list, global_l) {
1113 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001114
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001115 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 continue;
1117
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001118 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001120 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001121 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001122 return c;
1123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124
1125 /* Closest match */
1126 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001127 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 }
1129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001131 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001132
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001133 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134}
1135
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001136int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001138 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 struct l2cap_conn *conn;
1141 struct hci_conn *hcon;
1142 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001143 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001144 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001146 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001147 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001149 hdev = hci_get_route(dst, src);
1150 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 return -EHOSTUNREACH;
1152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001153 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001155 l2cap_chan_lock(chan);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001156
1157 /* PSM must be odd and lsb of upper byte must be 0 */
1158 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1159 chan->chan_type != L2CAP_CHAN_RAW) {
1160 err = -EINVAL;
1161 goto done;
1162 }
1163
1164 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1165 err = -EINVAL;
1166 goto done;
1167 }
1168
1169 switch (chan->mode) {
1170 case L2CAP_MODE_BASIC:
1171 break;
1172 case L2CAP_MODE_ERTM:
1173 case L2CAP_MODE_STREAMING:
1174 if (!disable_ertm)
1175 break;
1176 /* fall through */
1177 default:
1178 err = -ENOTSUPP;
1179 goto done;
1180 }
1181
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001182 lock_sock(sk);
1183
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001184 switch (sk->sk_state) {
1185 case BT_CONNECT:
1186 case BT_CONNECT2:
1187 case BT_CONFIG:
1188 /* Already connecting */
1189 err = 0;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001190 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001191 goto done;
1192
1193 case BT_CONNECTED:
1194 /* Already connected */
1195 err = -EISCONN;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001196 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001197 goto done;
1198
1199 case BT_OPEN:
1200 case BT_BOUND:
1201 /* Can connect */
1202 break;
1203
1204 default:
1205 err = -EBADFD;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001206 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001207 goto done;
1208 }
1209
1210 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001211 bacpy(&bt_sk(sk)->dst, dst);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001212
1213 release_sock(sk);
1214
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001215 chan->psm = psm;
1216 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001218 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001219
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001220 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001221 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001222 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001223 else
1224 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001225 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001226
Ville Tervo30e76272011-02-22 16:10:53 -03001227 if (IS_ERR(hcon)) {
1228 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001230 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231
1232 conn = l2cap_conn_add(hcon, 0);
1233 if (!conn) {
1234 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001235 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 goto done;
1237 }
1238
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 /* Update source addr of the socket */
1240 bacpy(src, conn->src);
1241
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001242 l2cap_chan_unlock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001243 l2cap_chan_add(conn, chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001244 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001245
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001246 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001247 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001250 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001251 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001252 if (l2cap_chan_check_security(chan))
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001253 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001254 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001255 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 }
1257
Ville Tervo30e76272011-02-22 16:10:53 -03001258 err = 0;
1259
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001261 l2cap_chan_unlock(chan);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001262 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 hci_dev_put(hdev);
1264 return err;
1265}
1266
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001267int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001268{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001269 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001270 DECLARE_WAITQUEUE(wait, current);
1271 int err = 0;
1272 int timeo = HZ/5;
1273
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001274 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001275 set_current_state(TASK_INTERRUPTIBLE);
1276 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001277 if (!timeo)
1278 timeo = HZ/5;
1279
1280 if (signal_pending(current)) {
1281 err = sock_intr_errno(timeo);
1282 break;
1283 }
1284
1285 release_sock(sk);
1286 timeo = schedule_timeout(timeo);
1287 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001288 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001289
1290 err = sock_error(sk);
1291 if (err)
1292 break;
1293 }
1294 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001295 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001296 return err;
1297}
1298
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001299static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001300{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001301 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1302 monitor_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001303
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001304 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001305
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001306 l2cap_chan_lock(chan);
1307
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001308 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001309 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001310 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001311 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001312 return;
1313 }
1314
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001315 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001316 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001317
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001318 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001319 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001320 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001321}
1322
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001323static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001324{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001325 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1326 retrans_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001327
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001328 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001329
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001330 l2cap_chan_lock(chan);
1331
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001332 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001333 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001334
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001335 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001336
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001337 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001338
1339 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001340 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001341}
1342
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001343static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001344{
1345 struct sk_buff *skb;
1346
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001347 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001348 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001349 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001350 break;
1351
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001352 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001353 kfree_skb(skb);
1354
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001355 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001356 }
1357
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001358 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001359 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001360}
1361
Szymon Janc67c9e842011-07-28 16:24:33 +02001362static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001363{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001364 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001365 u32 control;
1366 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001367
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001368 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001369 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001370 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001371 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001372
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001373 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001374 fcs = crc16(0, (u8 *)skb->data,
1375 skb->len - L2CAP_FCS_SIZE);
1376 put_unaligned_le16(fcs,
1377 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001378 }
1379
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001380 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001381
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001382 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001383 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001384}
1385
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001386static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001387{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001388 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001389 u16 fcs;
1390 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001391
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001392 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001393 if (!skb)
1394 return;
1395
Szymon Jancd1726b62011-11-16 09:32:20 +01001396 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001397 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001398 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001399
Szymon Jancd1726b62011-11-16 09:32:20 +01001400 skb = skb_queue_next(&chan->tx_q, skb);
1401 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001402
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001403 if (chan->remote_max_tx &&
1404 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001405 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001406 return;
1407 }
1408
1409 tx_skb = skb_clone(skb, GFP_ATOMIC);
1410 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001411
1412 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001413 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001414
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001415 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001416 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001417
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001418 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001419 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001420
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001421 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001422
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001423 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001424 fcs = crc16(0, (u8 *)tx_skb->data,
1425 tx_skb->len - L2CAP_FCS_SIZE);
1426 put_unaligned_le16(fcs,
1427 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001428 }
1429
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001430 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001431}
1432
Szymon Janc67c9e842011-07-28 16:24:33 +02001433static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001434{
1435 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001436 u16 fcs;
1437 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001438 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001439
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001440 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001441 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001442
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001443 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001444
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001445 if (chan->remote_max_tx &&
1446 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001447 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001448 break;
1449 }
1450
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001451 tx_skb = skb_clone(skb, GFP_ATOMIC);
1452
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001453 bt_cb(skb)->retries++;
1454
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001455 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001456 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001457
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001458 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001459 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001460
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001461 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001462 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001463
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001464 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001465
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001466 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001467 fcs = crc16(0, (u8 *)skb->data,
1468 tx_skb->len - L2CAP_FCS_SIZE);
1469 put_unaligned_le16(fcs, skb->data +
1470 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001471 }
1472
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001473 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001474
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001475 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001476
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001477 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001478
1479 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001480
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001481 if (bt_cb(skb)->retries == 1) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001482 chan->unacked_frames++;
Szymon Janc930fa4a2012-02-07 15:43:02 +01001483
1484 if (!nsent++)
1485 __clear_ack_timer(chan);
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001486 }
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301487
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001488 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001489
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001490 if (skb_queue_is_last(&chan->tx_q, skb))
1491 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001492 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001493 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001494 }
1495
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001496 return nsent;
1497}
1498
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001499static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001500{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001501 int ret;
1502
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001503 if (!skb_queue_empty(&chan->tx_q))
1504 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001505
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001506 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001507 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001508 return ret;
1509}
1510
Szymon Jancb17e73b2012-01-11 10:59:47 +01001511static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001512{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001513 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001514
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001515 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001516
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001517 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001518 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001519 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001520 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001521 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001522 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001523
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001524 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001525 return;
1526
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001527 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001528 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001529}
1530
Szymon Jancb17e73b2012-01-11 10:59:47 +01001531static void l2cap_send_ack(struct l2cap_chan *chan)
1532{
1533 __clear_ack_timer(chan);
1534 __l2cap_send_ack(chan);
1535}
1536
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001537static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001538{
1539 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001540 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001541
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001542 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001543 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001544
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001545 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001546 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001547
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001548 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001549}
1550
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001551static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
1552 struct msghdr *msg, int len,
1553 int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001555 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001556 struct sk_buff **frag;
1557 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001559 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001560 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
1562 sent += count;
1563 len -= count;
1564
1565 /* Continuation fragments (no L2CAP header) */
1566 frag = &skb_shinfo(skb)->frag_list;
1567 while (len) {
1568 count = min_t(unsigned int, conn->mtu, len);
1569
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001570 *frag = chan->ops->alloc_skb(chan, count,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001571 msg->msg_flags & MSG_DONTWAIT,
1572 &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001573
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001575 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001576 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1577 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001579 (*frag)->priority = skb->priority;
1580
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 sent += count;
1582 len -= count;
1583
1584 frag = &(*frag)->next;
1585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
1587 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001588}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001590static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1591 struct msghdr *msg, size_t len,
1592 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001593{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001594 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001595 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001596 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001597 struct l2cap_hdr *lh;
1598
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001599 BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001600
1601 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001602
1603 skb = chan->ops->alloc_skb(chan, count + hlen,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001604 msg->msg_flags & MSG_DONTWAIT, &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001605
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001606 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001607 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001608
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001609 skb->priority = priority;
1610
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001611 /* Create L2CAP header */
1612 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001613 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001614 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001615 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001616
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001617 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001618 if (unlikely(err < 0)) {
1619 kfree_skb(skb);
1620 return ERR_PTR(err);
1621 }
1622 return skb;
1623}
1624
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001625static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1626 struct msghdr *msg, size_t len,
1627 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001628{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001629 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001630 struct sk_buff *skb;
1631 int err, count, hlen = L2CAP_HDR_SIZE;
1632 struct l2cap_hdr *lh;
1633
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001634 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001635
1636 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001637
1638 skb = chan->ops->alloc_skb(chan, count + hlen,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001639 msg->msg_flags & MSG_DONTWAIT, &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001640
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001641 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001642 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001643
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001644 skb->priority = priority;
1645
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001646 /* Create L2CAP header */
1647 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001648 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001649 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1650
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001651 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001652 if (unlikely(err < 0)) {
1653 kfree_skb(skb);
1654 return ERR_PTR(err);
1655 }
1656 return skb;
1657}
1658
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001659static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1660 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001661 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001662{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001663 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001664 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001665 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001666 struct l2cap_hdr *lh;
1667
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001668 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001669
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001670 if (!conn)
1671 return ERR_PTR(-ENOTCONN);
1672
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001673 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1674 hlen = L2CAP_EXT_HDR_SIZE;
1675 else
1676 hlen = L2CAP_ENH_HDR_SIZE;
1677
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001678 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001679 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001680
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001681 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001682 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001683
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001684 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001685
1686 skb = chan->ops->alloc_skb(chan, count + hlen,
1687 msg->msg_flags & MSG_DONTWAIT, &err);
1688
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001689 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001690 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001691
1692 /* Create L2CAP header */
1693 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001694 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001695 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001696
1697 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1698
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001699 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001700 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001701
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001702 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001703 if (unlikely(err < 0)) {
1704 kfree_skb(skb);
1705 return ERR_PTR(err);
1706 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001707
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001708 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001709 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001710
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001711 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001712 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713}
1714
Szymon Janc67c9e842011-07-28 16:24:33 +02001715static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001716{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001717 struct sk_buff *skb;
1718 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001719 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001720 size_t size = 0;
1721
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001722 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001723 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001724 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001725 if (IS_ERR(skb))
1726 return PTR_ERR(skb);
1727
1728 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001729 len -= chan->remote_mps;
1730 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001731
1732 while (len > 0) {
1733 size_t buflen;
1734
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001735 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001736 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001737 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001738 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001739 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001740 buflen = len;
1741 }
1742
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001743 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001744 if (IS_ERR(skb)) {
1745 skb_queue_purge(&sar_queue);
1746 return PTR_ERR(skb);
1747 }
1748
1749 __skb_queue_tail(&sar_queue, skb);
1750 len -= buflen;
1751 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001752 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001753 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1754 if (chan->tx_send_head == NULL)
1755 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001756
1757 return size;
1758}
1759
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001760int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1761 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001762{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001763 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001764 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001765 int err;
1766
1767 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001768 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001769 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001770 if (IS_ERR(skb))
1771 return PTR_ERR(skb);
1772
1773 l2cap_do_send(chan, skb);
1774 return len;
1775 }
1776
1777 switch (chan->mode) {
1778 case L2CAP_MODE_BASIC:
1779 /* Check outgoing MTU */
1780 if (len > chan->omtu)
1781 return -EMSGSIZE;
1782
1783 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001784 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001785 if (IS_ERR(skb))
1786 return PTR_ERR(skb);
1787
1788 l2cap_do_send(chan, skb);
1789 err = len;
1790 break;
1791
1792 case L2CAP_MODE_ERTM:
1793 case L2CAP_MODE_STREAMING:
1794 /* Entire SDU fits into one PDU */
1795 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001796 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001797 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1798 0);
1799 if (IS_ERR(skb))
1800 return PTR_ERR(skb);
1801
1802 __skb_queue_tail(&chan->tx_q, skb);
1803
1804 if (chan->tx_send_head == NULL)
1805 chan->tx_send_head = skb;
1806
1807 } else {
1808 /* Segment SDU into multiples PDUs */
1809 err = l2cap_sar_segment_sdu(chan, msg, len);
1810 if (err < 0)
1811 return err;
1812 }
1813
1814 if (chan->mode == L2CAP_MODE_STREAMING) {
1815 l2cap_streaming_send(chan);
1816 err = len;
1817 break;
1818 }
1819
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001820 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1821 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001822 err = len;
1823 break;
1824 }
1825
1826 err = l2cap_ertm_send(chan);
1827 if (err >= 0)
1828 err = len;
1829
1830 break;
1831
1832 default:
1833 BT_DBG("bad state %1.1x", chan->mode);
1834 err = -EBADFD;
1835 }
1836
1837 return err;
1838}
1839
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840/* Copy frame to all raw sockets on that connection */
1841static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1842{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001844 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845
1846 BT_DBG("conn %p", conn);
1847
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001848 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001849
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001850 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001851 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001852 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001853 continue;
1854
1855 /* Don't send frame to the socket it came from */
1856 if (skb->sk == sk)
1857 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001858 nskb = skb_clone(skb, GFP_ATOMIC);
1859 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001860 continue;
1861
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001862 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 kfree_skb(nskb);
1864 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001865
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001866 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867}
1868
1869/* ---- L2CAP signalling commands ---- */
1870static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1871 u8 code, u8 ident, u16 dlen, void *data)
1872{
1873 struct sk_buff *skb, **frag;
1874 struct l2cap_cmd_hdr *cmd;
1875 struct l2cap_hdr *lh;
1876 int len, count;
1877
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001878 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1879 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880
1881 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1882 count = min_t(unsigned int, conn->mtu, len);
1883
1884 skb = bt_skb_alloc(count, GFP_ATOMIC);
1885 if (!skb)
1886 return NULL;
1887
1888 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001889 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001890
1891 if (conn->hcon->type == LE_LINK)
1892 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1893 else
1894 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
1896 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1897 cmd->code = code;
1898 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001899 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
1901 if (dlen) {
1902 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1903 memcpy(skb_put(skb, count), data, count);
1904 data += count;
1905 }
1906
1907 len -= skb->len;
1908
1909 /* Continuation fragments (no L2CAP header) */
1910 frag = &skb_shinfo(skb)->frag_list;
1911 while (len) {
1912 count = min_t(unsigned int, conn->mtu, len);
1913
1914 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1915 if (!*frag)
1916 goto fail;
1917
1918 memcpy(skb_put(*frag, count), data, count);
1919
1920 len -= count;
1921 data += count;
1922
1923 frag = &(*frag)->next;
1924 }
1925
1926 return skb;
1927
1928fail:
1929 kfree_skb(skb);
1930 return NULL;
1931}
1932
1933static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1934{
1935 struct l2cap_conf_opt *opt = *ptr;
1936 int len;
1937
1938 len = L2CAP_CONF_OPT_SIZE + opt->len;
1939 *ptr += len;
1940
1941 *type = opt->type;
1942 *olen = opt->len;
1943
1944 switch (opt->len) {
1945 case 1:
1946 *val = *((u8 *) opt->val);
1947 break;
1948
1949 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001950 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 break;
1952
1953 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001954 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 break;
1956
1957 default:
1958 *val = (unsigned long) opt->val;
1959 break;
1960 }
1961
1962 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1963 return len;
1964}
1965
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1967{
1968 struct l2cap_conf_opt *opt = *ptr;
1969
1970 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1971
1972 opt->type = type;
1973 opt->len = len;
1974
1975 switch (len) {
1976 case 1:
1977 *((u8 *) opt->val) = val;
1978 break;
1979
1980 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001981 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 break;
1983
1984 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001985 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 break;
1987
1988 default:
1989 memcpy(opt->val, (void *) val, len);
1990 break;
1991 }
1992
1993 *ptr += L2CAP_CONF_OPT_SIZE + len;
1994}
1995
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001996static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1997{
1998 struct l2cap_conf_efs efs;
1999
Szymon Janc1ec918c2011-11-16 09:32:21 +01002000 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002001 case L2CAP_MODE_ERTM:
2002 efs.id = chan->local_id;
2003 efs.stype = chan->local_stype;
2004 efs.msdu = cpu_to_le16(chan->local_msdu);
2005 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2006 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
2007 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
2008 break;
2009
2010 case L2CAP_MODE_STREAMING:
2011 efs.id = 1;
2012 efs.stype = L2CAP_SERV_BESTEFFORT;
2013 efs.msdu = cpu_to_le16(chan->local_msdu);
2014 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2015 efs.acc_lat = 0;
2016 efs.flush_to = 0;
2017 break;
2018
2019 default:
2020 return;
2021 }
2022
2023 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
2024 (unsigned long) &efs);
2025}
2026
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002027static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002028{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002029 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2030 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002031
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02002032 BT_DBG("chan %p", chan);
2033
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002034 l2cap_chan_lock(chan);
2035
Szymon Jancb17e73b2012-01-11 10:59:47 +01002036 __l2cap_send_ack(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002037
2038 l2cap_chan_unlock(chan);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002039
2040 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002041}
2042
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002043static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002044{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002045 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002046 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002047 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002048 chan->num_acked = 0;
2049 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002050
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002051 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2052 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2053 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002054
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002055 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002056
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002057 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002058}
2059
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002060static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2061{
2062 switch (mode) {
2063 case L2CAP_MODE_STREAMING:
2064 case L2CAP_MODE_ERTM:
2065 if (l2cap_mode_supported(mode, remote_feat_mask))
2066 return mode;
2067 /* fall through */
2068 default:
2069 return L2CAP_MODE_BASIC;
2070 }
2071}
2072
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002073static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2074{
2075 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2076}
2077
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002078static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2079{
2080 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2081}
2082
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002083static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2084{
2085 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002086 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002087 /* use extended control field */
2088 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002089 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2090 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002091 chan->tx_win = min_t(u16, chan->tx_win,
2092 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002093 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2094 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002095}
2096
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002097static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002100 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002102 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002104 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002106 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002107 goto done;
2108
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002109 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002110 case L2CAP_MODE_STREAMING:
2111 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002112 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002113 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002114
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002115 if (__l2cap_efs_supported(chan))
2116 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2117
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002118 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002119 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002120 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002121 break;
2122 }
2123
2124done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002125 if (chan->imtu != L2CAP_DEFAULT_MTU)
2126 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002127
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002128 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002129 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002130 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2131 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002132 break;
2133
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002134 rfc.mode = L2CAP_MODE_BASIC;
2135 rfc.txwin_size = 0;
2136 rfc.max_transmit = 0;
2137 rfc.retrans_timeout = 0;
2138 rfc.monitor_timeout = 0;
2139 rfc.max_pdu_size = 0;
2140
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002141 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2142 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002143 break;
2144
2145 case L2CAP_MODE_ERTM:
2146 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002147 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002148 rfc.retrans_timeout = 0;
2149 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002150
2151 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2152 L2CAP_EXT_HDR_SIZE -
2153 L2CAP_SDULEN_SIZE -
2154 L2CAP_FCS_SIZE);
2155 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002156
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002157 l2cap_txwin_setup(chan);
2158
2159 rfc.txwin_size = min_t(u16, chan->tx_win,
2160 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002161
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002162 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2163 (unsigned long) &rfc);
2164
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002165 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2166 l2cap_add_opt_efs(&ptr, chan);
2167
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002168 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002169 break;
2170
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002171 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002172 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002173 chan->fcs = L2CAP_FCS_NONE;
2174 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002175 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002176
2177 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2178 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2179 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002180 break;
2181
2182 case L2CAP_MODE_STREAMING:
2183 rfc.mode = L2CAP_MODE_STREAMING;
2184 rfc.txwin_size = 0;
2185 rfc.max_transmit = 0;
2186 rfc.retrans_timeout = 0;
2187 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002188
2189 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2190 L2CAP_EXT_HDR_SIZE -
2191 L2CAP_SDULEN_SIZE -
2192 L2CAP_FCS_SIZE);
2193 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002194
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002195 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2196 (unsigned long) &rfc);
2197
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002198 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2199 l2cap_add_opt_efs(&ptr, chan);
2200
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002201 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002202 break;
2203
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002204 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002205 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002206 chan->fcs = L2CAP_FCS_NONE;
2207 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002208 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002209 break;
2210 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002212 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002213 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214
2215 return ptr - data;
2216}
2217
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002218static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002220 struct l2cap_conf_rsp *rsp = data;
2221 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002222 void *req = chan->conf_req;
2223 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002224 int type, hint, olen;
2225 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002226 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002227 struct l2cap_conf_efs efs;
2228 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002229 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002230 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002231 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002233 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002234
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002235 while (len >= L2CAP_CONF_OPT_SIZE) {
2236 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002238 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002239 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002240
2241 switch (type) {
2242 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002243 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002244 break;
2245
2246 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002247 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002248 break;
2249
2250 case L2CAP_CONF_QOS:
2251 break;
2252
Marcel Holtmann6464f352007-10-20 13:39:51 +02002253 case L2CAP_CONF_RFC:
2254 if (olen == sizeof(rfc))
2255 memcpy(&rfc, (void *) val, olen);
2256 break;
2257
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002258 case L2CAP_CONF_FCS:
2259 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002260 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002261 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002262
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002263 case L2CAP_CONF_EFS:
2264 remote_efs = 1;
2265 if (olen == sizeof(efs))
2266 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002267 break;
2268
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002269 case L2CAP_CONF_EWS:
2270 if (!enable_hs)
2271 return -ECONNREFUSED;
2272
2273 set_bit(FLAG_EXT_CTRL, &chan->flags);
2274 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002275 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002276 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002277 break;
2278
2279 default:
2280 if (hint)
2281 break;
2282
2283 result = L2CAP_CONF_UNKNOWN;
2284 *((u8 *) ptr++) = type;
2285 break;
2286 }
2287 }
2288
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002289 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002290 goto done;
2291
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002292 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002293 case L2CAP_MODE_STREAMING:
2294 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002295 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002296 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002297 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002298 break;
2299 }
2300
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002301 if (remote_efs) {
2302 if (__l2cap_efs_supported(chan))
2303 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2304 else
2305 return -ECONNREFUSED;
2306 }
2307
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002308 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002309 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002310
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002311 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002312 }
2313
2314done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002315 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002316 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002317 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002318
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002319 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002320 return -ECONNREFUSED;
2321
2322 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2323 sizeof(rfc), (unsigned long) &rfc);
2324 }
2325
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002326 if (result == L2CAP_CONF_SUCCESS) {
2327 /* Configure output options and let the other side know
2328 * which ones we don't like. */
2329
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002330 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2331 result = L2CAP_CONF_UNACCEPT;
2332 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002333 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002334 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002335 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002336 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002337
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002338 if (remote_efs) {
2339 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2340 efs.stype != L2CAP_SERV_NOTRAFIC &&
2341 efs.stype != chan->local_stype) {
2342
2343 result = L2CAP_CONF_UNACCEPT;
2344
2345 if (chan->num_conf_req >= 1)
2346 return -ECONNREFUSED;
2347
2348 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002349 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002350 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002351 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002352 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002353 result = L2CAP_CONF_PENDING;
2354 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002355 }
2356 }
2357
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002358 switch (rfc.mode) {
2359 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002360 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002361 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002362 break;
2363
2364 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002365 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2366 chan->remote_tx_win = rfc.txwin_size;
2367 else
2368 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2369
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002370 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002371
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002372 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2373 chan->conn->mtu -
2374 L2CAP_EXT_HDR_SIZE -
2375 L2CAP_SDULEN_SIZE -
2376 L2CAP_FCS_SIZE);
2377 rfc.max_pdu_size = cpu_to_le16(size);
2378 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002379
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002380 rfc.retrans_timeout =
2381 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2382 rfc.monitor_timeout =
2383 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002384
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002385 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002386
2387 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2388 sizeof(rfc), (unsigned long) &rfc);
2389
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002390 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2391 chan->remote_id = efs.id;
2392 chan->remote_stype = efs.stype;
2393 chan->remote_msdu = le16_to_cpu(efs.msdu);
2394 chan->remote_flush_to =
2395 le32_to_cpu(efs.flush_to);
2396 chan->remote_acc_lat =
2397 le32_to_cpu(efs.acc_lat);
2398 chan->remote_sdu_itime =
2399 le32_to_cpu(efs.sdu_itime);
2400 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2401 sizeof(efs), (unsigned long) &efs);
2402 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002403 break;
2404
2405 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002406 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2407 chan->conn->mtu -
2408 L2CAP_EXT_HDR_SIZE -
2409 L2CAP_SDULEN_SIZE -
2410 L2CAP_FCS_SIZE);
2411 rfc.max_pdu_size = cpu_to_le16(size);
2412 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002413
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002414 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002415
2416 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2417 sizeof(rfc), (unsigned long) &rfc);
2418
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002419 break;
2420
2421 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002422 result = L2CAP_CONF_UNACCEPT;
2423
2424 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002425 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002426 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002427
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002428 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002429 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002430 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002431 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002432 rsp->result = cpu_to_le16(result);
2433 rsp->flags = cpu_to_le16(0x0000);
2434
2435 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436}
2437
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002438static 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 -03002439{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002440 struct l2cap_conf_req *req = data;
2441 void *ptr = req->data;
2442 int type, olen;
2443 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002444 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002445 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002446
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002447 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002448
2449 while (len >= L2CAP_CONF_OPT_SIZE) {
2450 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2451
2452 switch (type) {
2453 case L2CAP_CONF_MTU:
2454 if (val < L2CAP_DEFAULT_MIN_MTU) {
2455 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002456 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002457 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002458 chan->imtu = val;
2459 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002460 break;
2461
2462 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002463 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002464 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002465 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002466 break;
2467
2468 case L2CAP_CONF_RFC:
2469 if (olen == sizeof(rfc))
2470 memcpy(&rfc, (void *)val, olen);
2471
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002472 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002473 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002474 return -ECONNREFUSED;
2475
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002476 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002477
2478 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2479 sizeof(rfc), (unsigned long) &rfc);
2480 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002481
2482 case L2CAP_CONF_EWS:
2483 chan->tx_win = min_t(u16, val,
2484 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002485 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2486 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002487 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002488
2489 case L2CAP_CONF_EFS:
2490 if (olen == sizeof(efs))
2491 memcpy(&efs, (void *)val, olen);
2492
2493 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2494 efs.stype != L2CAP_SERV_NOTRAFIC &&
2495 efs.stype != chan->local_stype)
2496 return -ECONNREFUSED;
2497
2498 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2499 sizeof(efs), (unsigned long) &efs);
2500 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002501 }
2502 }
2503
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002504 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002505 return -ECONNREFUSED;
2506
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002507 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002508
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002509 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002510 switch (rfc.mode) {
2511 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002512 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2513 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2514 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002515
2516 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2517 chan->local_msdu = le16_to_cpu(efs.msdu);
2518 chan->local_sdu_itime =
2519 le32_to_cpu(efs.sdu_itime);
2520 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2521 chan->local_flush_to =
2522 le32_to_cpu(efs.flush_to);
2523 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002524 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002525
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002526 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002527 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002528 }
2529 }
2530
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002531 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002532 req->flags = cpu_to_le16(0x0000);
2533
2534 return ptr - data;
2535}
2536
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002537static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538{
2539 struct l2cap_conf_rsp *rsp = data;
2540 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002542 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002544 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002545 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002546 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547
2548 return ptr - data;
2549}
2550
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002551void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002552{
2553 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002554 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002555 u8 buf[128];
2556
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002557 rsp.scid = cpu_to_le16(chan->dcid);
2558 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002559 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2560 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2561 l2cap_send_cmd(conn, chan->ident,
2562 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2563
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002564 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002565 return;
2566
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002567 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2568 l2cap_build_conf_req(chan, buf), buf);
2569 chan->num_conf_req++;
2570}
2571
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002572static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002573{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002574 int type, olen;
2575 unsigned long val;
2576 struct l2cap_conf_rfc rfc;
2577
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002578 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002579
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002580 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002581 return;
2582
2583 while (len >= L2CAP_CONF_OPT_SIZE) {
2584 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2585
2586 switch (type) {
2587 case L2CAP_CONF_RFC:
2588 if (olen == sizeof(rfc))
2589 memcpy(&rfc, (void *)val, olen);
2590 goto done;
2591 }
2592 }
2593
Mat Martineau36e999a2011-12-08 17:23:21 -08002594 /* Use sane default values in case a misbehaving remote device
2595 * did not send an RFC option.
2596 */
2597 rfc.mode = chan->mode;
2598 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2599 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2600 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2601
2602 BT_ERR("Expected RFC option was not found, using defaults");
2603
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002604done:
2605 switch (rfc.mode) {
2606 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002607 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2608 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2609 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002610 break;
2611 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002612 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002613 }
2614}
2615
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002616static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2617{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002618 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002619
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002620 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002621 return 0;
2622
2623 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2624 cmd->ident == conn->info_ident) {
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02002625 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002626
2627 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002628 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002629
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002630 l2cap_conn_start(conn);
2631 }
2632
2633 return 0;
2634}
2635
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2637{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2639 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002640 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002641 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002642 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643
2644 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002645 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
2647 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2648
2649 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002650 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2651 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 result = L2CAP_CR_BAD_PSM;
2653 goto sendresp;
2654 }
2655
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002656 parent = pchan->sk;
2657
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002658 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002659 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002660
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002661 /* Check if the ACL is secure enough (if not SDP) */
2662 if (psm != cpu_to_le16(0x0001) &&
2663 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002664 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002665 result = L2CAP_CR_SEC_BLOCK;
2666 goto response;
2667 }
2668
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 result = L2CAP_CR_NO_MEM;
2670
2671 /* Check for backlog size */
2672 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002673 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 goto response;
2675 }
2676
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002677 chan = pchan->ops->new_connection(pchan->data);
2678 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 goto response;
2680
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002681 sk = chan->sk;
2682
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002684 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002686 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 goto response;
2688 }
2689
2690 hci_conn_hold(conn->hcon);
2691
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 bacpy(&bt_sk(sk)->src, conn->src);
2693 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002694 chan->psm = psm;
2695 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002697 bt_accept_enqueue(parent, sk);
2698
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002699 __l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002700
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002701 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002703 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002705 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706
Marcel Holtmann984947d2009-02-06 23:35:19 +01002707 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002708 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002709 if (bt_sk(sk)->defer_setup) {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002710 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002711 result = L2CAP_CR_PEND;
2712 status = L2CAP_CS_AUTHOR_PEND;
2713 parent->sk_data_ready(parent, 0);
2714 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002715 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002716 result = L2CAP_CR_SUCCESS;
2717 status = L2CAP_CS_NO_INFO;
2718 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002719 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002720 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002721 result = L2CAP_CR_PEND;
2722 status = L2CAP_CS_AUTHEN_PEND;
2723 }
2724 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002725 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002726 result = L2CAP_CR_PEND;
2727 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 }
2729
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002731 release_sock(parent);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002732 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733
2734sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002735 rsp.scid = cpu_to_le16(scid);
2736 rsp.dcid = cpu_to_le16(dcid);
2737 rsp.result = cpu_to_le16(result);
2738 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002740
2741 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2742 struct l2cap_info_req info;
2743 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2744
2745 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2746 conn->info_ident = l2cap_get_ident(conn);
2747
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08002748 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002749
2750 l2cap_send_cmd(conn, conn->info_ident,
2751 L2CAP_INFO_REQ, sizeof(info), &info);
2752 }
2753
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002754 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002755 result == L2CAP_CR_SUCCESS) {
2756 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002757 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002758 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002759 l2cap_build_conf_req(chan, buf), buf);
2760 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002761 }
2762
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 return 0;
2764}
2765
2766static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2767{
2768 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2769 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002770 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 u8 req[128];
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002772 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773
2774 scid = __le16_to_cpu(rsp->scid);
2775 dcid = __le16_to_cpu(rsp->dcid);
2776 result = __le16_to_cpu(rsp->result);
2777 status = __le16_to_cpu(rsp->status);
2778
Andrei Emeltchenko1b009c92012-02-21 12:54:54 +02002779 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
2780 dcid, scid, result, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002782 mutex_lock(&conn->chan_lock);
2783
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 if (scid) {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002785 chan = __l2cap_get_chan_by_scid(conn, scid);
2786 if (!chan) {
2787 err = -EFAULT;
2788 goto unlock;
2789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 } else {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002791 chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
2792 if (!chan) {
2793 err = -EFAULT;
2794 goto unlock;
2795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 }
2797
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002798 err = 0;
2799
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002800 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002801
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 switch (result) {
2803 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002804 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002805 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002806 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002807 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002808
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002809 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002810 break;
2811
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002813 l2cap_build_conf_req(chan, req), req);
2814 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 break;
2816
2817 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002818 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 break;
2820
2821 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002822 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 break;
2824 }
2825
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002826 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002827
2828unlock:
2829 mutex_unlock(&conn->chan_lock);
2830
2831 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832}
2833
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002834static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002835{
2836 /* FCS is enabled only in ERTM or streaming mode, if one or both
2837 * sides request it.
2838 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002839 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002840 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002841 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002842 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002843}
2844
Al Viro88219a02007-07-29 00:17:25 -07002845static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846{
2847 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2848 u16 dcid, flags;
2849 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002850 struct l2cap_chan *chan;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002851 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852
2853 dcid = __le16_to_cpu(req->dcid);
2854 flags = __le16_to_cpu(req->flags);
2855
2856 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2857
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002858 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002859 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 return -ENOENT;
2861
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002862 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002863
David S. Miller033b1142011-07-21 13:38:42 -07002864 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002865 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002866
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002867 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2868 rej.scid = cpu_to_le16(chan->scid);
2869 rej.dcid = cpu_to_le16(chan->dcid);
2870
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002871 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2872 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002873 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002874 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002875
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002876 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002877 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002878 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002879 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002880 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002881 L2CAP_CONF_REJECT, flags), rsp);
2882 goto unlock;
2883 }
2884
2885 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002886 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2887 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888
2889 if (flags & 0x0001) {
2890 /* Incomplete config. Send empty response. */
2891 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002892 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002893 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 goto unlock;
2895 }
2896
2897 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002898 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002899 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002900 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002902 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002904 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002905 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002906
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002907 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002908 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002909
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002910 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002911 goto unlock;
2912
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002913 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002914 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002915
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002916 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002917
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002918 chan->next_tx_seq = 0;
2919 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002920 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002921 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002922 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002923
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02002924 l2cap_chan_ready(chan);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002925 goto unlock;
2926 }
2927
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002928 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002929 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002931 l2cap_build_conf_req(chan, buf), buf);
2932 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 }
2934
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002935 /* Got Conf Rsp PENDING from remote side and asume we sent
2936 Conf Rsp PENDING in the code above */
2937 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2938 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2939
2940 /* check compatibility */
2941
2942 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2943 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2944
2945 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002946 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002947 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2948 }
2949
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950unlock:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002951 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 return 0;
2953}
2954
2955static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2956{
2957 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2958 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002959 struct l2cap_chan *chan;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002960 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961
2962 scid = __le16_to_cpu(rsp->scid);
2963 flags = __le16_to_cpu(rsp->flags);
2964 result = __le16_to_cpu(rsp->result);
2965
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002966 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2967 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002969 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002970 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 return 0;
2972
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002973 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002974
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 switch (result) {
2976 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002977 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002978 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 break;
2980
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002981 case L2CAP_CONF_PENDING:
2982 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2983
2984 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2985 char buf[64];
2986
2987 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2988 buf, &result);
2989 if (len < 0) {
2990 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2991 goto done;
2992 }
2993
2994 /* check compatibility */
2995
2996 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2997 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2998
2999 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02003000 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03003001 L2CAP_CONF_SUCCESS, 0x0000), buf);
3002 }
3003 goto done;
3004
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003006 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003007 char req[64];
3008
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003009 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003010 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003011 goto done;
3012 }
3013
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003014 /* throw out any old stored conf requests */
3015 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03003016 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
3017 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003018 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003019 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003020 goto done;
3021 }
3022
3023 l2cap_send_cmd(conn, l2cap_get_ident(conn),
3024 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003025 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003026 if (result != L2CAP_CONF_SUCCESS)
3027 goto done;
3028 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 }
3030
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09003031 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003032 l2cap_chan_set_err(chan, ECONNRESET);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +02003033
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08003034 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003035 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 goto done;
3037 }
3038
3039 if (flags & 0x01)
3040 goto done;
3041
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003042 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003044 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003045 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003046
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003047 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003048 chan->next_tx_seq = 0;
3049 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003050 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003051 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003052 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003053
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02003054 l2cap_chan_ready(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 }
3056
3057done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003058 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 return 0;
3060}
3061
3062static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3063{
3064 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3065 struct l2cap_disconn_rsp rsp;
3066 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003067 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068 struct sock *sk;
3069
3070 scid = __le16_to_cpu(req->scid);
3071 dcid = __le16_to_cpu(req->dcid);
3072
3073 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3074
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003075 mutex_lock(&conn->chan_lock);
3076
3077 chan = __l2cap_get_chan_by_scid(conn, dcid);
3078 if (!chan) {
3079 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003083 l2cap_chan_lock(chan);
3084
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003085 sk = chan->sk;
3086
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003087 rsp.dcid = cpu_to_le16(chan->scid);
3088 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3090
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003091 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092 sk->sk_shutdown = SHUTDOWN_MASK;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003093 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003095 l2cap_chan_del(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003096
3097 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003099 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003100
3101 mutex_unlock(&conn->chan_lock);
3102
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 return 0;
3104}
3105
3106static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3107{
3108 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3109 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003110 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111
3112 scid = __le16_to_cpu(rsp->scid);
3113 dcid = __le16_to_cpu(rsp->dcid);
3114
3115 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3116
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003117 mutex_lock(&conn->chan_lock);
3118
3119 chan = __l2cap_get_chan_by_scid(conn, scid);
3120 if (!chan) {
3121 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003125 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003126
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003127 l2cap_chan_del(chan, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003128
3129 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003131 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003132
3133 mutex_unlock(&conn->chan_lock);
3134
Linus Torvalds1da177e2005-04-16 15:20:36 -07003135 return 0;
3136}
3137
3138static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3139{
3140 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 u16 type;
3142
3143 type = __le16_to_cpu(req->type);
3144
3145 BT_DBG("type 0x%4.4x", type);
3146
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003147 if (type == L2CAP_IT_FEAT_MASK) {
3148 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003149 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003150 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3151 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3152 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003153 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003154 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3155 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003156 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003157 feat_mask |= L2CAP_FEAT_EXT_FLOW
3158 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003159
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003160 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003161 l2cap_send_cmd(conn, cmd->ident,
3162 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003163 } else if (type == L2CAP_IT_FIXED_CHAN) {
3164 u8 buf[12];
3165 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003166
3167 if (enable_hs)
3168 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3169 else
3170 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3171
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003172 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3173 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003174 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003175 l2cap_send_cmd(conn, cmd->ident,
3176 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003177 } else {
3178 struct l2cap_info_rsp rsp;
3179 rsp.type = cpu_to_le16(type);
3180 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3181 l2cap_send_cmd(conn, cmd->ident,
3182 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3183 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184
3185 return 0;
3186}
3187
3188static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3189{
3190 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3191 u16 type, result;
3192
3193 type = __le16_to_cpu(rsp->type);
3194 result = __le16_to_cpu(rsp->result);
3195
3196 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3197
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003198 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3199 if (cmd->ident != conn->info_ident ||
3200 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3201 return 0;
3202
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02003203 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003204
Ville Tervoadb08ed2010-08-04 09:43:33 +03003205 if (result != L2CAP_IR_SUCCESS) {
3206 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3207 conn->info_ident = 0;
3208
3209 l2cap_conn_start(conn);
3210
3211 return 0;
3212 }
3213
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003214 switch (type) {
3215 case L2CAP_IT_FEAT_MASK:
Harvey Harrison83985312008-05-02 16:25:46 -07003216 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003217
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003218 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003219 struct l2cap_info_req req;
3220 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3221
3222 conn->info_ident = l2cap_get_ident(conn);
3223
3224 l2cap_send_cmd(conn, conn->info_ident,
3225 L2CAP_INFO_REQ, sizeof(req), &req);
3226 } else {
3227 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3228 conn->info_ident = 0;
3229
3230 l2cap_conn_start(conn);
3231 }
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003232 break;
3233
3234 case L2CAP_IT_FIXED_CHAN:
3235 conn->fixed_chan_mask = rsp->data[0];
Marcel Holtmann984947d2009-02-06 23:35:19 +01003236 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003237 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003238
3239 l2cap_conn_start(conn);
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003240 break;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003241 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003242
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 return 0;
3244}
3245
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003246static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3247 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3248 void *data)
3249{
3250 struct l2cap_create_chan_req *req = data;
3251 struct l2cap_create_chan_rsp rsp;
3252 u16 psm, scid;
3253
3254 if (cmd_len != sizeof(*req))
3255 return -EPROTO;
3256
3257 if (!enable_hs)
3258 return -EINVAL;
3259
3260 psm = le16_to_cpu(req->psm);
3261 scid = le16_to_cpu(req->scid);
3262
3263 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3264
3265 /* Placeholder: Always reject */
3266 rsp.dcid = 0;
3267 rsp.scid = cpu_to_le16(scid);
3268 rsp.result = L2CAP_CR_NO_MEM;
3269 rsp.status = L2CAP_CS_NO_INFO;
3270
3271 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3272 sizeof(rsp), &rsp);
3273
3274 return 0;
3275}
3276
3277static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3278 struct l2cap_cmd_hdr *cmd, void *data)
3279{
3280 BT_DBG("conn %p", conn);
3281
3282 return l2cap_connect_rsp(conn, cmd, data);
3283}
3284
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003285static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3286 u16 icid, u16 result)
3287{
3288 struct l2cap_move_chan_rsp rsp;
3289
3290 BT_DBG("icid %d, result %d", icid, result);
3291
3292 rsp.icid = cpu_to_le16(icid);
3293 rsp.result = cpu_to_le16(result);
3294
3295 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3296}
3297
3298static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3299 struct l2cap_chan *chan, u16 icid, u16 result)
3300{
3301 struct l2cap_move_chan_cfm cfm;
3302 u8 ident;
3303
3304 BT_DBG("icid %d, result %d", icid, result);
3305
3306 ident = l2cap_get_ident(conn);
3307 if (chan)
3308 chan->ident = ident;
3309
3310 cfm.icid = cpu_to_le16(icid);
3311 cfm.result = cpu_to_le16(result);
3312
3313 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3314}
3315
3316static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3317 u16 icid)
3318{
3319 struct l2cap_move_chan_cfm_rsp rsp;
3320
3321 BT_DBG("icid %d", icid);
3322
3323 rsp.icid = cpu_to_le16(icid);
3324 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3325}
3326
3327static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3328 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3329{
3330 struct l2cap_move_chan_req *req = data;
3331 u16 icid = 0;
3332 u16 result = L2CAP_MR_NOT_ALLOWED;
3333
3334 if (cmd_len != sizeof(*req))
3335 return -EPROTO;
3336
3337 icid = le16_to_cpu(req->icid);
3338
3339 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3340
3341 if (!enable_hs)
3342 return -EINVAL;
3343
3344 /* Placeholder: Always refuse */
3345 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3346
3347 return 0;
3348}
3349
3350static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3351 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3352{
3353 struct l2cap_move_chan_rsp *rsp = data;
3354 u16 icid, result;
3355
3356 if (cmd_len != sizeof(*rsp))
3357 return -EPROTO;
3358
3359 icid = le16_to_cpu(rsp->icid);
3360 result = le16_to_cpu(rsp->result);
3361
3362 BT_DBG("icid %d, result %d", icid, result);
3363
3364 /* Placeholder: Always unconfirmed */
3365 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3366
3367 return 0;
3368}
3369
3370static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3371 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3372{
3373 struct l2cap_move_chan_cfm *cfm = data;
3374 u16 icid, result;
3375
3376 if (cmd_len != sizeof(*cfm))
3377 return -EPROTO;
3378
3379 icid = le16_to_cpu(cfm->icid);
3380 result = le16_to_cpu(cfm->result);
3381
3382 BT_DBG("icid %d, result %d", icid, result);
3383
3384 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3385
3386 return 0;
3387}
3388
3389static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3390 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3391{
3392 struct l2cap_move_chan_cfm_rsp *rsp = data;
3393 u16 icid;
3394
3395 if (cmd_len != sizeof(*rsp))
3396 return -EPROTO;
3397
3398 icid = le16_to_cpu(rsp->icid);
3399
3400 BT_DBG("icid %d", icid);
3401
3402 return 0;
3403}
3404
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003405static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003406 u16 to_multiplier)
3407{
3408 u16 max_latency;
3409
3410 if (min > max || min < 6 || max > 3200)
3411 return -EINVAL;
3412
3413 if (to_multiplier < 10 || to_multiplier > 3200)
3414 return -EINVAL;
3415
3416 if (max >= to_multiplier * 8)
3417 return -EINVAL;
3418
3419 max_latency = (to_multiplier * 8 / max) - 1;
3420 if (latency > 499 || latency > max_latency)
3421 return -EINVAL;
3422
3423 return 0;
3424}
3425
3426static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3427 struct l2cap_cmd_hdr *cmd, u8 *data)
3428{
3429 struct hci_conn *hcon = conn->hcon;
3430 struct l2cap_conn_param_update_req *req;
3431 struct l2cap_conn_param_update_rsp rsp;
3432 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003433 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003434
3435 if (!(hcon->link_mode & HCI_LM_MASTER))
3436 return -EINVAL;
3437
3438 cmd_len = __le16_to_cpu(cmd->len);
3439 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3440 return -EPROTO;
3441
3442 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003443 min = __le16_to_cpu(req->min);
3444 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003445 latency = __le16_to_cpu(req->latency);
3446 to_multiplier = __le16_to_cpu(req->to_multiplier);
3447
3448 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3449 min, max, latency, to_multiplier);
3450
3451 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003452
3453 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3454 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003455 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3456 else
3457 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3458
3459 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3460 sizeof(rsp), &rsp);
3461
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003462 if (!err)
3463 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3464
Claudio Takahaside731152011-02-11 19:28:55 -02003465 return 0;
3466}
3467
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003468static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3469 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3470{
3471 int err = 0;
3472
3473 switch (cmd->code) {
3474 case L2CAP_COMMAND_REJ:
3475 l2cap_command_rej(conn, cmd, data);
3476 break;
3477
3478 case L2CAP_CONN_REQ:
3479 err = l2cap_connect_req(conn, cmd, data);
3480 break;
3481
3482 case L2CAP_CONN_RSP:
3483 err = l2cap_connect_rsp(conn, cmd, data);
3484 break;
3485
3486 case L2CAP_CONF_REQ:
3487 err = l2cap_config_req(conn, cmd, cmd_len, data);
3488 break;
3489
3490 case L2CAP_CONF_RSP:
3491 err = l2cap_config_rsp(conn, cmd, data);
3492 break;
3493
3494 case L2CAP_DISCONN_REQ:
3495 err = l2cap_disconnect_req(conn, cmd, data);
3496 break;
3497
3498 case L2CAP_DISCONN_RSP:
3499 err = l2cap_disconnect_rsp(conn, cmd, data);
3500 break;
3501
3502 case L2CAP_ECHO_REQ:
3503 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3504 break;
3505
3506 case L2CAP_ECHO_RSP:
3507 break;
3508
3509 case L2CAP_INFO_REQ:
3510 err = l2cap_information_req(conn, cmd, data);
3511 break;
3512
3513 case L2CAP_INFO_RSP:
3514 err = l2cap_information_rsp(conn, cmd, data);
3515 break;
3516
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003517 case L2CAP_CREATE_CHAN_REQ:
3518 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3519 break;
3520
3521 case L2CAP_CREATE_CHAN_RSP:
3522 err = l2cap_create_channel_rsp(conn, cmd, data);
3523 break;
3524
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003525 case L2CAP_MOVE_CHAN_REQ:
3526 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3527 break;
3528
3529 case L2CAP_MOVE_CHAN_RSP:
3530 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3531 break;
3532
3533 case L2CAP_MOVE_CHAN_CFM:
3534 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3535 break;
3536
3537 case L2CAP_MOVE_CHAN_CFM_RSP:
3538 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3539 break;
3540
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003541 default:
3542 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3543 err = -EINVAL;
3544 break;
3545 }
3546
3547 return err;
3548}
3549
3550static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3551 struct l2cap_cmd_hdr *cmd, u8 *data)
3552{
3553 switch (cmd->code) {
3554 case L2CAP_COMMAND_REJ:
3555 return 0;
3556
3557 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003558 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003559
3560 case L2CAP_CONN_PARAM_UPDATE_RSP:
3561 return 0;
3562
3563 default:
3564 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3565 return -EINVAL;
3566 }
3567}
3568
3569static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3570 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571{
3572 u8 *data = skb->data;
3573 int len = skb->len;
3574 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003575 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576
3577 l2cap_raw_recv(conn, skb);
3578
3579 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003580 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3582 data += L2CAP_CMD_HDR_SIZE;
3583 len -= L2CAP_CMD_HDR_SIZE;
3584
Al Viro88219a02007-07-29 00:17:25 -07003585 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586
Al Viro88219a02007-07-29 00:17:25 -07003587 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 -07003588
Al Viro88219a02007-07-29 00:17:25 -07003589 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 BT_DBG("corrupted command");
3591 break;
3592 }
3593
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003594 if (conn->hcon->type == LE_LINK)
3595 err = l2cap_le_sig_cmd(conn, &cmd, data);
3596 else
3597 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
3599 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003600 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003601
3602 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603
3604 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003605 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003606 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3607 }
3608
Al Viro88219a02007-07-29 00:17:25 -07003609 data += cmd_len;
3610 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611 }
3612
3613 kfree_skb(skb);
3614}
3615
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003616static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003617{
3618 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003619 int hdr_size;
3620
3621 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3622 hdr_size = L2CAP_EXT_HDR_SIZE;
3623 else
3624 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003625
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003626 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003627 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003628 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3629 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3630
3631 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003632 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003633 }
3634 return 0;
3635}
3636
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003637static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003638{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003639 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003640
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003641 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003642
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003643 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003644
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003645 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003646 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003647 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003648 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003649 }
3650
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003651 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003652 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003653
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003654 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003655
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003656 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003657 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003658 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003659 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003660 }
3661}
3662
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003663static 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 -03003664{
3665 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003666 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003667
3668 bt_cb(skb)->tx_seq = tx_seq;
3669 bt_cb(skb)->sar = sar;
3670
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003671 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003672
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003673 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003674
Szymon Janc039d9572011-11-16 09:32:19 +01003675 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003676 if (bt_cb(next_skb)->tx_seq == tx_seq)
3677 return -EINVAL;
3678
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003679 next_tx_seq_offset = __seq_offset(chan,
3680 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003681
3682 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003683 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003684 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003685 }
3686
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003687 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003688 next_skb = NULL;
3689 else
3690 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3691 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003692
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003693 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003694
3695 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003696}
3697
Mat Martineau84084a32011-07-22 14:54:00 -07003698static void append_skb_frag(struct sk_buff *skb,
3699 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003700{
Mat Martineau84084a32011-07-22 14:54:00 -07003701 /* skb->len reflects data in skb as well as all fragments
3702 * skb->data_len reflects only data in fragments
3703 */
3704 if (!skb_has_frag_list(skb))
3705 skb_shinfo(skb)->frag_list = new_frag;
3706
3707 new_frag->next = NULL;
3708
3709 (*last_frag)->next = new_frag;
3710 *last_frag = new_frag;
3711
3712 skb->len += new_frag->len;
3713 skb->data_len += new_frag->len;
3714 skb->truesize += new_frag->truesize;
3715}
3716
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003717static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003718{
3719 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003720
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003721 switch (__get_ctrl_sar(chan, control)) {
3722 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003723 if (chan->sdu)
3724 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003725
Mat Martineau84084a32011-07-22 14:54:00 -07003726 err = chan->ops->recv(chan->data, skb);
3727 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003728
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003729 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003730 if (chan->sdu)
3731 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003732
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003733 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003734 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003735
Mat Martineau84084a32011-07-22 14:54:00 -07003736 if (chan->sdu_len > chan->imtu) {
3737 err = -EMSGSIZE;
3738 break;
3739 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003740
Mat Martineau84084a32011-07-22 14:54:00 -07003741 if (skb->len >= chan->sdu_len)
3742 break;
3743
3744 chan->sdu = skb;
3745 chan->sdu_last_frag = skb;
3746
3747 skb = NULL;
3748 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003749 break;
3750
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003751 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003752 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003753 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003754
Mat Martineau84084a32011-07-22 14:54:00 -07003755 append_skb_frag(chan->sdu, skb,
3756 &chan->sdu_last_frag);
3757 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003758
Mat Martineau84084a32011-07-22 14:54:00 -07003759 if (chan->sdu->len >= chan->sdu_len)
3760 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003761
Mat Martineau84084a32011-07-22 14:54:00 -07003762 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003763 break;
3764
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003765 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003766 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003767 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003768
Mat Martineau84084a32011-07-22 14:54:00 -07003769 append_skb_frag(chan->sdu, skb,
3770 &chan->sdu_last_frag);
3771 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003772
Mat Martineau84084a32011-07-22 14:54:00 -07003773 if (chan->sdu->len != chan->sdu_len)
3774 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003775
Mat Martineau84084a32011-07-22 14:54:00 -07003776 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003777
Mat Martineau84084a32011-07-22 14:54:00 -07003778 if (!err) {
3779 /* Reassembly complete */
3780 chan->sdu = NULL;
3781 chan->sdu_last_frag = NULL;
3782 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003783 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003784 break;
3785 }
3786
Mat Martineau84084a32011-07-22 14:54:00 -07003787 if (err) {
3788 kfree_skb(skb);
3789 kfree_skb(chan->sdu);
3790 chan->sdu = NULL;
3791 chan->sdu_last_frag = NULL;
3792 chan->sdu_len = 0;
3793 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003794
Mat Martineau84084a32011-07-22 14:54:00 -07003795 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003796}
3797
Mat Martineau26f880d2011-07-07 09:39:01 -07003798static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003799{
Mat Martineau26f880d2011-07-07 09:39:01 -07003800 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003801
Mat Martineau26f880d2011-07-07 09:39:01 -07003802 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3803
Szymon Janc77f918b2012-01-11 10:59:48 +01003804 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003805}
3806
3807static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3808{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003809 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003810
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003811 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003812 goto done;
3813
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003814 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003815 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003816 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003817 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003818 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003819
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003820 __clear_retrans_timer(chan);
3821 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003822
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003823 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003824
3825done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003826 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3827 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003828
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003829 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003830}
3831
Mat Martineaue3281402011-07-07 09:39:02 -07003832void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003833{
Mat Martineaue3281402011-07-07 09:39:02 -07003834 if (chan->mode == L2CAP_MODE_ERTM) {
3835 if (busy)
3836 l2cap_ertm_enter_local_busy(chan);
3837 else
3838 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003839 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003840}
3841
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003842static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003843{
3844 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003845 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003846
Mat Martineaue3281402011-07-07 09:39:02 -07003847 while ((skb = skb_peek(&chan->srej_q)) &&
3848 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3849 int err;
3850
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003851 if (bt_cb(skb)->tx_seq != tx_seq)
3852 break;
3853
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003854 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003855 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003856 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003857
3858 if (err < 0) {
3859 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3860 break;
3861 }
3862
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003863 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3864 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003865 }
3866}
3867
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003868static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003869{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003870 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003871 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003872
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003873 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003874 if (l->tx_seq == tx_seq) {
3875 list_del(&l->list);
3876 kfree(l);
3877 return;
3878 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003879 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003880 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003881 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003882 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003883 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003884 }
3885}
3886
Szymon Jancaef89f22011-11-16 09:32:18 +01003887static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003888{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003889 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003890 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003891
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003892 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003893 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003894 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003895 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003896
3897 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003898 if (!new)
3899 return -ENOMEM;
3900
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003901 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003902
3903 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3904
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003905 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003906 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003907
3908 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003909
3910 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003911}
3912
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003913static 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 -03003914{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003915 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003916 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003917 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003918 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003919 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003920 int err = 0;
3921
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003922 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 -03003923 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003924
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003925 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003926 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003927 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003928 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003929 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003930 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003931 }
3932
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003933 chan->expected_ack_seq = req_seq;
3934 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003935
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003936 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003937
3938 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003939 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003940 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003941 goto drop;
3942 }
3943
Szymon Janc77f918b2012-01-11 10:59:48 +01003944 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3945 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3946 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003947 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003948 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003949
Mat Martineau02f1b642011-06-29 14:35:19 -07003950 if (tx_seq == chan->expected_tx_seq)
3951 goto expected;
3952
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003953 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003954 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003955
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003956 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003957 struct srej_list, list);
3958 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003959 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003960 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003961
3962 list_del(&first->list);
3963 kfree(first);
3964
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003965 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003966 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003967 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003968 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003969 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003970 }
3971 } else {
3972 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003973
3974 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003975 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003976 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003977
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003978 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003979 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003980 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003981 return 0;
3982 }
3983 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003984
3985 err = l2cap_send_srejframe(chan, tx_seq);
3986 if (err < 0) {
3987 l2cap_send_disconn_req(chan->conn, chan, -err);
3988 return err;
3989 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003990 }
3991 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003992 expected_tx_seq_offset = __seq_offset(chan,
3993 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003994
3995 /* duplicated tx_seq */
3996 if (tx_seq_offset < expected_tx_seq_offset)
3997 goto drop;
3998
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003999 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004000
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004001 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004002
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03004003 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004004 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004005
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004006 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004007 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004008
Szymon Janc0ef3ef02012-01-11 10:59:46 +01004009 /* Set P-bit only if there are some I-frames to ack. */
4010 if (__clear_ack_timer(chan))
4011 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03004012
Szymon Jancaef89f22011-11-16 09:32:18 +01004013 err = l2cap_send_srejframe(chan, tx_seq);
4014 if (err < 0) {
4015 l2cap_send_disconn_req(chan->conn, chan, -err);
4016 return err;
4017 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004018 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004019 return 0;
4020
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004021expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004022 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004023
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004024 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03004025 bt_cb(skb)->tx_seq = tx_seq;
4026 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004027 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004028 return 0;
4029 }
4030
Mat Martineau84084a32011-07-22 14:54:00 -07004031 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004032 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4033
Mat Martineaue3281402011-07-07 09:39:02 -07004034 if (err < 0) {
4035 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4036 return err;
4037 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03004038
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004039 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004040 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004041 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03004042 }
4043
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03004044
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004045 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
4046 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004047 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03004048 else
4049 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03004050
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004051 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03004052
4053drop:
4054 kfree_skb(skb);
4055 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004056}
4057
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004058static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004059{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004060 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004061 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004062
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004063 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004064 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004065
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004066 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004067 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4068 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4069 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004070 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004071 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004072
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004073 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004074 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004075 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004076 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004077 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004078
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004079 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004080 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004081
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004082 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004083 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004084
4085 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004086 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004087 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004088 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004089
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004090 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4091 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004092 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004093 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004094 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004095 }
4096}
4097
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004098static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004099{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004100 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004101
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004102 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004103
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004104 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004105
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004106 chan->expected_ack_seq = tx_seq;
4107 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004108
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004109 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004110 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004111 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004112 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004113 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004114
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004115 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4116 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004117 }
4118}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004119static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004120{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004121 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004122
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004123 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004124
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004125 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004126
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004127 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004128 chan->expected_ack_seq = tx_seq;
4129 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004130
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004131 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004132 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004133
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004134 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004135
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004136 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004137 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004138 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004139 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004140 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004141 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004142 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004143 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004144 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004145 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004146 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004147 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004148 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004149 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004150 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004151 }
4152 }
4153}
4154
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004155static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004156{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004157 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004158
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004159 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004160
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004161 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004162 chan->expected_ack_seq = tx_seq;
4163 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004164
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004165 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004166 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004167
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004168 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004169 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004170 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004171 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004172 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004173 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004174
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004175 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004176 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004177 } else {
4178 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4179 l2cap_send_sframe(chan, rx_control);
4180 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004181}
4182
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004183static 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 -03004184{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004185 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004186
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004187 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004188 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004189 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004190 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004191 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004192 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004193 }
4194
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004195 switch (__get_ctrl_super(chan, rx_control)) {
4196 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004197 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004198 break;
4199
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004200 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004201 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004202 break;
4203
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004204 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004205 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004206 break;
4207
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004208 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004209 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004210 break;
4211 }
4212
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004213 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004214 return 0;
4215}
4216
Szymon Janccad8f1d2012-01-23 10:06:05 +01004217static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004218{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004219 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004220 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004221 int len, next_tx_seq_offset, req_seq_offset;
4222
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004223 control = __get_control(chan, skb->data);
4224 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004225 len = skb->len;
4226
4227 /*
4228 * We can just drop the corrupted I-frame here.
4229 * Receiver will miss it and start proper recovery
4230 * procedures and ask retransmission.
4231 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004232 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004233 goto drop;
4234
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004235 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004236 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004237
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004238 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004239 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004240
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004241 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004242 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004243 goto drop;
4244 }
4245
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004246 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004247
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004248 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4249
4250 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4251 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004252
4253 /* check for invalid req-seq */
4254 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004255 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004256 goto drop;
4257 }
4258
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004259 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004260 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004261 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004262 goto drop;
4263 }
4264
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004265 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004266 } else {
4267 if (len != 0) {
4268 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004269 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004270 goto drop;
4271 }
4272
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004273 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004274 }
4275
4276 return 0;
4277
4278drop:
4279 kfree_skb(skb);
4280 return 0;
4281}
4282
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4284{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004285 struct l2cap_chan *chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004286 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004287 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004288 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004290 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004291 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 BT_DBG("unknown cid 0x%4.4x", cid);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004293 /* Drop packet and return */
Dan Carpenter33790132012-02-28 09:52:46 +03004294 kfree_skb(skb);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004295 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 }
4297
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004298 l2cap_chan_lock(chan);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004299
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004300 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004302 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 goto drop;
4304
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004305 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004306 case L2CAP_MODE_BASIC:
4307 /* If socket recv buffers overflows we drop data here
4308 * which is *bad* because L2CAP has to be reliable.
4309 * But we don't have any other choice. L2CAP doesn't
4310 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004312 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004313 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004315 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004316 goto done;
4317 break;
4318
4319 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004320 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004321
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004322 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004323
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004324 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004325 control = __get_control(chan, skb->data);
4326 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004327 len = skb->len;
4328
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004329 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004330 goto drop;
4331
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004332 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004333 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004334
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004335 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004336 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004337
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004338 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004339 goto drop;
4340
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004341 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004342
Mat Martineau84084a32011-07-22 14:54:00 -07004343 if (chan->expected_tx_seq != tx_seq) {
4344 /* Frame(s) missing - must discard partial SDU */
4345 kfree_skb(chan->sdu);
4346 chan->sdu = NULL;
4347 chan->sdu_last_frag = NULL;
4348 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004349
Mat Martineau84084a32011-07-22 14:54:00 -07004350 /* TODO: Notify userland of missing data */
4351 }
4352
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004353 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004354
4355 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4356 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004357
4358 goto done;
4359
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004360 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004361 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004362 break;
4363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364
4365drop:
4366 kfree_skb(skb);
4367
4368done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004369 l2cap_chan_unlock(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +02004370
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 return 0;
4372}
4373
Al Viro8e036fc2007-07-29 00:16:36 -07004374static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004376 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004378 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4379 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 goto drop;
4381
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004382 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004384 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 goto drop;
4386
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004387 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 goto drop;
4389
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004390 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004391 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392
4393drop:
4394 kfree_skb(skb);
4395
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 return 0;
4397}
4398
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004399static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4400{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004401 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004402
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004403 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4404 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004405 goto drop;
4406
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004407 BT_DBG("chan %p, len %d", chan, skb->len);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004408
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004409 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004410 goto drop;
4411
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004412 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004413 goto drop;
4414
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004415 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004416 return 0;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004417
4418drop:
4419 kfree_skb(skb);
4420
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004421 return 0;
4422}
4423
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4425{
4426 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004427 u16 cid, len;
4428 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429
4430 skb_pull(skb, L2CAP_HDR_SIZE);
4431 cid = __le16_to_cpu(lh->cid);
4432 len = __le16_to_cpu(lh->len);
4433
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004434 if (len != skb->len) {
4435 kfree_skb(skb);
4436 return;
4437 }
4438
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4440
4441 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004442 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004443 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 l2cap_sig_channel(conn, skb);
4445 break;
4446
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004447 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004448 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 skb_pull(skb, 2);
4450 l2cap_conless_channel(conn, psm, skb);
4451 break;
4452
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004453 case L2CAP_CID_LE_DATA:
4454 l2cap_att_channel(conn, cid, skb);
4455 break;
4456
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004457 case L2CAP_CID_SMP:
4458 if (smp_sig_channel(conn, skb))
4459 l2cap_conn_del(conn->hcon, EACCES);
4460 break;
4461
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 default:
4463 l2cap_data_channel(conn, cid, skb);
4464 break;
4465 }
4466}
4467
4468/* ---- L2CAP interface with lower layer (HCI) ---- */
4469
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004470int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471{
4472 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004473 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474
Linus Torvalds1da177e2005-04-16 15:20:36 -07004475 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4476
4477 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004478 read_lock(&chan_list_lock);
4479 list_for_each_entry(c, &chan_list, global_l) {
4480 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004481
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004482 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483 continue;
4484
4485 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004486 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004487 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004488 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004490 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4491 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004492 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004493 lm2 |= HCI_LM_MASTER;
4494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004496 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497
4498 return exact ? lm1 : lm2;
4499}
4500
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004501int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502{
Marcel Holtmann01394182006-07-03 10:02:46 +02004503 struct l2cap_conn *conn;
4504
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4506
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 conn = l2cap_conn_add(hcon, status);
4509 if (conn)
4510 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004511 } else
Joe Perchese1750722011-06-29 18:18:29 -07004512 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513
4514 return 0;
4515}
4516
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004517int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004518{
4519 struct l2cap_conn *conn = hcon->l2cap_data;
4520
4521 BT_DBG("hcon %p", hcon);
4522
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004523 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004524 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004525 return conn->disc_reason;
4526}
4527
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004528int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004529{
4530 BT_DBG("hcon %p reason %d", hcon, reason);
4531
Joe Perchese1750722011-06-29 18:18:29 -07004532 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 return 0;
4534}
4535
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004536static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004537{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004538 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004539 return;
4540
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004541 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004542 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004543 __clear_chan_timer(chan);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004544 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004545 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004546 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004547 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004548 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004549 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004550 }
4551}
4552
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004553int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004555 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004556 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557
Marcel Holtmann01394182006-07-03 10:02:46 +02004558 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004560
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 BT_DBG("conn %p", conn);
4562
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004563 if (hcon->type == LE_LINK) {
4564 smp_distribute_keys(conn, 0);
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02004565 cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004566 }
4567
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004568 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004570 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004571 l2cap_chan_lock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004573 BT_DBG("chan->scid %d", chan->scid);
4574
4575 if (chan->scid == L2CAP_CID_LE_DATA) {
4576 if (!status && encrypt) {
4577 chan->sec_level = hcon->sec_level;
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02004578 l2cap_chan_ready(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004579 }
4580
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004581 l2cap_chan_unlock(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004582 continue;
4583 }
4584
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004585 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004586 l2cap_chan_unlock(chan);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004587 continue;
4588 }
4589
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004590 if (!status && (chan->state == BT_CONNECTED ||
4591 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004592 l2cap_check_encryption(chan, encrypt);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004593 l2cap_chan_unlock(chan);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004594 continue;
4595 }
4596
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004597 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004598 if (!status) {
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +02004599 l2cap_send_conn_req(chan);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004600 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004601 __clear_chan_timer(chan);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004602 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004603 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004604 } else if (chan->state == BT_CONNECT2) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004605 struct sock *sk = chan->sk;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004606 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004607 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004608
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004609 lock_sock(sk);
4610
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004611 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004612 if (bt_sk(sk)->defer_setup) {
4613 struct sock *parent = bt_sk(sk)->parent;
4614 res = L2CAP_CR_PEND;
4615 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004616 if (parent)
4617 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004618 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004619 __l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004620 res = L2CAP_CR_SUCCESS;
4621 stat = L2CAP_CS_NO_INFO;
4622 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004623 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004624 __l2cap_state_change(chan, BT_DISCONN);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004625 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004626 res = L2CAP_CR_SEC_BLOCK;
4627 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004628 }
4629
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004630 release_sock(sk);
4631
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004632 rsp.scid = cpu_to_le16(chan->dcid);
4633 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004634 rsp.result = cpu_to_le16(res);
4635 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004636 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4637 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 }
4639
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004640 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 }
4642
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004643 mutex_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004644
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 return 0;
4646}
4647
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004648int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649{
4650 struct l2cap_conn *conn = hcon->l2cap_data;
4651
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004652 if (!conn)
4653 conn = l2cap_conn_add(hcon, 0);
4654
4655 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004656 goto drop;
4657
4658 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4659
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004660 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004662 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004663 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 int len;
4665
4666 if (conn->rx_len) {
4667 BT_ERR("Unexpected start frame (len %d)", skb->len);
4668 kfree_skb(conn->rx_skb);
4669 conn->rx_skb = NULL;
4670 conn->rx_len = 0;
4671 l2cap_conn_unreliable(conn, ECOMM);
4672 }
4673
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004674 /* Start fragment always begin with Basic L2CAP header */
4675 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 BT_ERR("Frame is too short (len %d)", skb->len);
4677 l2cap_conn_unreliable(conn, ECOMM);
4678 goto drop;
4679 }
4680
4681 hdr = (struct l2cap_hdr *) skb->data;
4682 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004683 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684
4685 if (len == skb->len) {
4686 /* Complete frame received */
4687 l2cap_recv_frame(conn, skb);
4688 return 0;
4689 }
4690
4691 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4692
4693 if (skb->len > len) {
4694 BT_ERR("Frame is too long (len %d, expected len %d)",
4695 skb->len, len);
4696 l2cap_conn_unreliable(conn, ECOMM);
4697 goto drop;
4698 }
4699
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004700 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004701
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004702 if (chan && chan->sk) {
4703 struct sock *sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004704 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004705
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004706 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004707 BT_ERR("Frame exceeding recv MTU (len %d, "
4708 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004709 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004710 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004711 l2cap_conn_unreliable(conn, ECOMM);
4712 goto drop;
4713 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004714 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004715 }
4716
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004718 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4719 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 goto drop;
4721
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004722 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004723 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 conn->rx_len = len - skb->len;
4725 } else {
4726 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4727
4728 if (!conn->rx_len) {
4729 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4730 l2cap_conn_unreliable(conn, ECOMM);
4731 goto drop;
4732 }
4733
4734 if (skb->len > conn->rx_len) {
4735 BT_ERR("Fragment is too long (len %d, expected %d)",
4736 skb->len, conn->rx_len);
4737 kfree_skb(conn->rx_skb);
4738 conn->rx_skb = NULL;
4739 conn->rx_len = 0;
4740 l2cap_conn_unreliable(conn, ECOMM);
4741 goto drop;
4742 }
4743
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004744 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004745 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 conn->rx_len -= skb->len;
4747
4748 if (!conn->rx_len) {
4749 /* Complete frame received */
4750 l2cap_recv_frame(conn, conn->rx_skb);
4751 conn->rx_skb = NULL;
4752 }
4753 }
4754
4755drop:
4756 kfree_skb(skb);
4757 return 0;
4758}
4759
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004760static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004762 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004764 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004766 list_for_each_entry(c, &chan_list, global_l) {
4767 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004769 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 +01004770 batostr(&bt_sk(sk)->src),
4771 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004772 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004773 c->scid, c->dcid, c->imtu, c->omtu,
4774 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004775 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004777 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004778
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004779 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004780}
4781
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004782static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4783{
4784 return single_open(file, l2cap_debugfs_show, inode->i_private);
4785}
4786
4787static const struct file_operations l2cap_debugfs_fops = {
4788 .open = l2cap_debugfs_open,
4789 .read = seq_read,
4790 .llseek = seq_lseek,
4791 .release = single_release,
4792};
4793
4794static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004796int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797{
4798 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004799
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004800 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 if (err < 0)
4802 return err;
4803
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004804 if (bt_debugfs) {
4805 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4806 bt_debugfs, NULL, &l2cap_debugfs_fops);
4807 if (!l2cap_debugfs)
4808 BT_ERR("Failed to create L2CAP debug file");
4809 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812}
4813
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004814void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004816 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004817 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818}
4819
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004820module_param(disable_ertm, bool, 0644);
4821MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");