blob: a57d96afa245e78987a0a86df04abe69cb5c8926 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Gustavo F. Padovan590051d2011-12-18 13:39:33 -02006 Copyright (C) 2011 ProFUSION Embedded Systems
Linus Torvalds1da177e2005-04-16 15:20:36 -07007
8 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation;
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
17 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090023 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 SOFTWARE IS DISCLAIMED.
26*/
27
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020028/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31
32#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080033#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/errno.h>
35#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/sched.h>
37#include <linux/slab.h>
38#include <linux/poll.h>
39#include <linux/fcntl.h>
40#include <linux/init.h>
41#include <linux/interrupt.h>
42#include <linux/socket.h>
43#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080045#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010046#include <linux/debugfs.h>
47#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030048#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030049#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <net/sock.h>
51
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/unaligned.h>
53
54#include <net/bluetooth/bluetooth.h>
55#include <net/bluetooth/hci_core.h>
56#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030057#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Rusty Russelleb939922011-12-19 14:08:01 +000059bool disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020060
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070061static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070062static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Johannes Bergb5ad8b72011-06-01 08:54:45 +020064static LIST_HEAD(chan_list);
65static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
68 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030069static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
70 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030071static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030072static void l2cap_send_disconn_req(struct l2cap_conn *conn,
73 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Marcel Holtmann01394182006-07-03 10:02:46 +020075/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030076
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030077static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020078{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020079 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030080
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020081 list_for_each_entry(c, &conn->chan_l, list) {
82 if (c->dcid == cid)
83 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020084 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020085 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020086}
87
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030088static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020089{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020090 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030091
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020092 list_for_each_entry(c, &conn->chan_l, list) {
93 if (c->scid == cid)
94 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020095 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +020096 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020097}
98
99/* Find channel with given SCID.
100 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300101static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200102{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300103 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300104
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200105 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300106 c = __l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200107 mutex_unlock(&conn->chan_lock);
108
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300109 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200110}
111
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300112static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200113{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200114 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300115
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200116 list_for_each_entry(c, &conn->chan_l, list) {
117 if (c->ident == ident)
118 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200119 }
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200120 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200121}
122
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300123static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200124{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300125 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300126
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200127 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300128 c = __l2cap_get_chan_by_ident(conn, ident);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200129 mutex_unlock(&conn->chan_lock);
130
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300131 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200132}
133
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300134static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300135{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300136 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300137
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300138 list_for_each_entry(c, &chan_list, global_l) {
139 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100140 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300141 }
Szymon Janc250938c2011-11-16 09:32:22 +0100142 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300143}
144
145int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
146{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300147 int err;
148
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200149 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300150
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300151 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300152 err = -EADDRINUSE;
153 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300154 }
155
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300156 if (psm) {
157 chan->psm = psm;
158 chan->sport = psm;
159 err = 0;
160 } else {
161 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300162
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300163 err = -EINVAL;
164 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300165 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300166 chan->psm = cpu_to_le16(p);
167 chan->sport = cpu_to_le16(p);
168 err = 0;
169 break;
170 }
171 }
172
173done:
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200174 write_unlock(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300175 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300176}
177
178int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
179{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200180 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300181
182 chan->scid = scid;
183
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200184 write_unlock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300185
186 return 0;
187}
188
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300189static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200190{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300191 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200192
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300193 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300194 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200195 return cid;
196 }
197
198 return 0;
199}
200
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200201static void __l2cap_state_change(struct l2cap_chan *chan, int state)
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300202{
Andrei Emeltchenko42d2d872012-02-17 11:40:57 +0200203 BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200204 state_to_string(state));
205
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300206 chan->state = state;
207 chan->ops->state_change(chan->data, state);
208}
209
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200210static void l2cap_state_change(struct l2cap_chan *chan, int state)
211{
212 struct sock *sk = chan->sk;
213
214 lock_sock(sk);
215 __l2cap_state_change(chan, state);
216 release_sock(sk);
217}
218
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200219static inline void __l2cap_chan_set_err(struct l2cap_chan *chan, int err)
220{
221 struct sock *sk = chan->sk;
222
223 sk->sk_err = err;
224}
225
226static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
227{
228 struct sock *sk = chan->sk;
229
230 lock_sock(sk);
231 __l2cap_chan_set_err(chan, err);
232 release_sock(sk);
233}
234
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300235static void l2cap_chan_timeout(struct work_struct *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300236{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300237 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
238 chan_timer.work);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200239 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300240 int reason;
241
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200242 BT_DBG("chan %p state %s", chan, state_to_string(chan->state));
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300243
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200244 mutex_lock(&conn->chan_lock);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200245 l2cap_chan_lock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300246
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300247 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300248 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300249 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300250 chan->sec_level != BT_SECURITY_SDP)
251 reason = ECONNREFUSED;
252 else
253 reason = ETIMEDOUT;
254
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300255 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300256
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200257 l2cap_chan_unlock(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300258
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300259 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200260 mutex_unlock(&conn->chan_lock);
261
Ulisses Furquim371fd832011-12-21 20:02:36 -0200262 l2cap_chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300263}
264
Gustavo Padovaneef1d9b2012-03-25 13:59:16 -0300265struct l2cap_chan *l2cap_chan_create(void)
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. Padovan333055f2011-12-22 15:14:39 -0200275 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300276 list_add(&chan->global_l, &chan_list);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200277 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300278
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300279 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300280
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300281 chan->state = BT_OPEN;
282
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300283 atomic_set(&chan->refcnt, 1);
284
Gustavo Padovaneef1d9b2012-03-25 13:59:16 -0300285 BT_DBG("chan %p", chan);
Szymon Jancabc545b2011-11-03 16:05:44 +0100286
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300287 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200288}
289
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300290void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300291{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200292 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300293 list_del(&chan->global_l);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200294 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300295
Ulisses Furquim371fd832011-12-21 20:02:36 -0200296 l2cap_chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300297}
298
Andrei Emeltchenko14a28492012-03-23 16:31:49 +0200299static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200300{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300301 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Andrei Emeltchenko097db762012-03-09 14:16:17 +0200302 __le16_to_cpu(chan->psm), chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200303
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200304 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100305
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300306 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200307
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200308 switch (chan->chan_type) {
309 case L2CAP_CHAN_CONN_ORIENTED:
Ville Tervob62f3282011-02-10 22:38:50 -0300310 if (conn->hcon->type == LE_LINK) {
311 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300312 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300313 chan->scid = L2CAP_CID_LE_DATA;
314 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300315 } else {
316 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300317 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300318 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300319 }
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200320 break;
321
322 case L2CAP_CHAN_CONN_LESS:
Marcel Holtmann01394182006-07-03 10:02:46 +0200323 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300324 chan->scid = L2CAP_CID_CONN_LESS;
325 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300326 chan->omtu = L2CAP_DEFAULT_MTU;
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200327 break;
328
329 default:
Marcel Holtmann01394182006-07-03 10:02:46 +0200330 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300331 chan->scid = L2CAP_CID_SIGNALING;
332 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300333 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200334 }
335
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300336 chan->local_id = L2CAP_BESTEFFORT_ID;
337 chan->local_stype = L2CAP_SERV_BESTEFFORT;
338 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
339 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
340 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
341 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
342
Ulisses Furquim371fd832011-12-21 20:02:36 -0200343 l2cap_chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300344
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200345 list_add(&chan->list, &conn->chan_l);
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200346}
347
Andrei Emeltchenko14a28492012-03-23 16:31:49 +0200348static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Andrei Emeltchenko643162a2012-02-22 17:11:55 +0200349{
350 mutex_lock(&conn->chan_lock);
351 __l2cap_chan_add(conn, chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200352 mutex_unlock(&conn->chan_lock);
Marcel Holtmann01394182006-07-03 10:02:46 +0200353}
354
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300355static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200356{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300357 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300358 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200359 struct sock *parent = bt_sk(sk)->parent;
360
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300361 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200362
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300363 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200364
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900365 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300366 /* Delete from channel list */
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200367 list_del(&chan->list);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200368
Ulisses Furquim371fd832011-12-21 20:02:36 -0200369 l2cap_chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300370
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300371 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200372 hci_conn_put(conn->hcon);
373 }
374
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200375 lock_sock(sk);
376
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200377 __l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200378 sock_set_flag(sk, SOCK_ZAPPED);
379
380 if (err)
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200381 __l2cap_chan_set_err(chan, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200382
383 if (parent) {
384 bt_accept_unlink(sk);
385 parent->sk_data_ready(parent, 0);
386 } else
387 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300388
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200389 release_sock(sk);
390
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300391 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
392 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300393 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300394
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300395 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300396
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300397 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300398 struct srej_list *l, *tmp;
399
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300400 __clear_retrans_timer(chan);
401 __clear_monitor_timer(chan);
402 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300403
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300404 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300405
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300406 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300407 list_del(&l->list);
408 kfree(l);
409 }
410 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200411}
412
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300413static void l2cap_chan_cleanup_listen(struct sock *parent)
414{
415 struct sock *sk;
416
417 BT_DBG("parent %p", parent);
418
419 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300420 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300421 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200422
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200423 l2cap_chan_lock(chan);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300424 __clear_chan_timer(chan);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300425 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200426 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200427
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300428 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300429 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300430}
431
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300432void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300433{
434 struct l2cap_conn *conn = chan->conn;
435 struct sock *sk = chan->sk;
436
Andrei Emeltchenkoe05dcc32012-02-17 11:40:56 +0200437 BT_DBG("chan %p state %s sk %p", chan,
438 state_to_string(chan->state), sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300439
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300440 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300441 case BT_LISTEN:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200442 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300443 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300444
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200445 __l2cap_state_change(chan, BT_CLOSED);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300446 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200447 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300448 break;
449
450 case BT_CONNECTED:
451 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300452 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300453 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300454 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300455 l2cap_send_disconn_req(conn, chan, reason);
456 } else
457 l2cap_chan_del(chan, reason);
458 break;
459
460 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300461 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300462 conn->hcon->type == ACL_LINK) {
463 struct l2cap_conn_rsp rsp;
464 __u16 result;
465
466 if (bt_sk(sk)->defer_setup)
467 result = L2CAP_CR_SEC_BLOCK;
468 else
469 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300470 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300471
472 rsp.scid = cpu_to_le16(chan->dcid);
473 rsp.dcid = cpu_to_le16(chan->scid);
474 rsp.result = cpu_to_le16(result);
475 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
476 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
477 sizeof(rsp), &rsp);
478 }
479
480 l2cap_chan_del(chan, reason);
481 break;
482
483 case BT_CONNECT:
484 case BT_DISCONN:
485 l2cap_chan_del(chan, reason);
486 break;
487
488 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200489 lock_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300490 sock_set_flag(sk, SOCK_ZAPPED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200491 release_sock(sk);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300492 break;
493 }
494}
495
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300496static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530497{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300498 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300499 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530500 case BT_SECURITY_HIGH:
501 return HCI_AT_DEDICATED_BONDING_MITM;
502 case BT_SECURITY_MEDIUM:
503 return HCI_AT_DEDICATED_BONDING;
504 default:
505 return HCI_AT_NO_BONDING;
506 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300507 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300508 if (chan->sec_level == BT_SECURITY_LOW)
509 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530510
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300511 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530512 return HCI_AT_NO_BONDING_MITM;
513 else
514 return HCI_AT_NO_BONDING;
515 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300516 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530517 case BT_SECURITY_HIGH:
518 return HCI_AT_GENERAL_BONDING_MITM;
519 case BT_SECURITY_MEDIUM:
520 return HCI_AT_GENERAL_BONDING;
521 default:
522 return HCI_AT_NO_BONDING;
523 }
524 }
525}
526
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200527/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200528int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200529{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300530 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100531 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200532
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300533 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100534
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300535 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200536}
537
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200538static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200539{
540 u8 id;
541
542 /* Get next available identificator.
543 * 1 - 128 are used by kernel.
544 * 129 - 199 are reserved.
545 * 200 - 254 are used by utilities like l2ping, etc.
546 */
547
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200548 spin_lock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200549
550 if (++conn->tx_ident > 128)
551 conn->tx_ident = 1;
552
553 id = conn->tx_ident;
554
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200555 spin_unlock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200556
557 return id;
558}
559
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300560static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200561{
562 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200563 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200564
565 BT_DBG("code 0x%2.2x", code);
566
567 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300568 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200569
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200570 if (lmp_no_flush_capable(conn->hcon->hdev))
571 flags = ACL_START_NO_FLUSH;
572 else
573 flags = ACL_START;
574
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700575 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200576 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700577
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200578 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200579}
580
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200581static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
582{
583 struct hci_conn *hcon = chan->conn->hcon;
584 u16 flags;
585
586 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
587 skb->priority);
588
589 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
590 lmp_no_flush_capable(hcon->hdev))
591 flags = ACL_START_NO_FLUSH;
592 else
593 flags = ACL_START;
594
595 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
596 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597}
598
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300599static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300600{
601 struct sk_buff *skb;
602 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300603 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300604 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300605
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300606 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300607 return;
608
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300609 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
610 hlen = L2CAP_EXT_HDR_SIZE;
611 else
612 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300613
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300614 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300615 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300616
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300617 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300618
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300619 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300620
621 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300622
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300623 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300624 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300625
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300626 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300627 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300628
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300629 skb = bt_skb_alloc(count, GFP_ATOMIC);
630 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300631 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300632
633 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300634 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300635 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300636
637 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300638
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300639 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300640 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
641 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300642 }
643
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200644 skb->priority = HCI_PRIO_MAX;
645 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300646}
647
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300648static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300649{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300650 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300651 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300652 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300653 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300654 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300655
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300656 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300657
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300658 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300659}
660
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300661static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300662{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300663 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300664}
665
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200666static void l2cap_send_conn_req(struct l2cap_chan *chan)
667{
668 struct l2cap_conn *conn = chan->conn;
669 struct l2cap_conn_req req;
670
671 req.scid = cpu_to_le16(chan->scid);
672 req.psm = chan->psm;
673
674 chan->ident = l2cap_get_ident(conn);
675
676 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
677
678 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
679}
680
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300681static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200682{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300683 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200684
685 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100686 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
687 return;
688
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200689 if (l2cap_chan_check_security(chan) &&
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200690 __l2cap_no_conn_pending(chan))
691 l2cap_send_conn_req(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200692 } else {
693 struct l2cap_info_req req;
694 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
695
696 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
697 conn->info_ident = l2cap_get_ident(conn);
698
Marcel Holtmannba13ccd2012-03-01 14:25:33 -0800699 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200700
701 l2cap_send_cmd(conn, conn->info_ident,
702 L2CAP_INFO_REQ, sizeof(req), &req);
703 }
704}
705
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300706static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
707{
708 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300709 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300710 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
711
712 switch (mode) {
713 case L2CAP_MODE_ERTM:
714 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
715 case L2CAP_MODE_STREAMING:
716 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
717 default:
718 return 0x00;
719 }
720}
721
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300722static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300723{
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200724 struct sock *sk = chan->sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300725 struct l2cap_disconn_req req;
726
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300727 if (!conn)
728 return;
729
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300730 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300731 __clear_retrans_timer(chan);
732 __clear_monitor_timer(chan);
733 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300734 }
735
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300736 req.dcid = cpu_to_le16(chan->dcid);
737 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300738 l2cap_send_cmd(conn, l2cap_get_ident(conn),
739 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300740
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200741 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200742 __l2cap_state_change(chan, BT_DISCONN);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200743 __l2cap_chan_set_err(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200744 release_sock(sk);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300745}
746
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200748static void l2cap_conn_start(struct l2cap_conn *conn)
749{
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200750 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200751
752 BT_DBG("conn %p", conn);
753
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200754 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200755
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200756 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300757 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300758
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200759 l2cap_chan_lock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200760
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300761 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200762 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200763 continue;
764 }
765
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300766 if (chan->state == BT_CONNECT) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200767 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300768 !__l2cap_no_conn_pending(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200769 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300770 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200771 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300772
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300773 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
774 && test_bit(CONF_STATE2_DEVICE,
775 &chan->conf_state)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300776 l2cap_chan_close(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200777 l2cap_chan_unlock(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300778 continue;
779 }
780
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +0200781 l2cap_send_conn_req(chan);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300782
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300783 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200784 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300785 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300786 rsp.scid = cpu_to_le16(chan->dcid);
787 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200788
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200789 if (l2cap_chan_check_security(chan)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200790 lock_sock(sk);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100791 if (bt_sk(sk)->defer_setup) {
792 struct sock *parent = bt_sk(sk)->parent;
793 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
794 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000795 if (parent)
796 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100797
798 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200799 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100800 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
801 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
802 }
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200803 release_sock(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200804 } else {
805 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
806 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
807 }
808
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300809 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
810 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300811
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300812 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300813 rsp.result != L2CAP_CR_SUCCESS) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200814 l2cap_chan_unlock(chan);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300815 continue;
816 }
817
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300818 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300819 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300820 l2cap_build_conf_req(chan, buf), buf);
821 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200822 }
823
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200824 l2cap_chan_unlock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200825 }
826
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200827 mutex_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200828}
829
Ville Tervob62f3282011-02-10 22:38:50 -0300830/* Find socket with cid and source bdaddr.
831 * Returns closest match, locked.
832 */
Andrei Emeltchenkod9b88702012-03-12 12:13:08 +0200833static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
834 bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300835{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300836 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300837
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300838 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300839
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300840 list_for_each_entry(c, &chan_list, global_l) {
841 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300842
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300843 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300844 continue;
845
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300846 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300847 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300848 if (!bacmp(&bt_sk(sk)->src, src)) {
849 read_unlock(&chan_list_lock);
850 return c;
851 }
Ville Tervob62f3282011-02-10 22:38:50 -0300852
853 /* Closest match */
854 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300855 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300856 }
857 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300858
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300859 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300860
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300861 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300862}
863
864static void l2cap_le_conn_ready(struct l2cap_conn *conn)
865{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300866 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300867 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300868
869 BT_DBG("");
870
871 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300872 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300873 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300874 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300875 return;
876
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300877 parent = pchan->sk;
878
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300879 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300880
Ville Tervob62f3282011-02-10 22:38:50 -0300881 /* Check for backlog size */
882 if (sk_acceptq_is_full(parent)) {
883 BT_DBG("backlog full %d", parent->sk_ack_backlog);
884 goto clean;
885 }
886
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300887 chan = pchan->ops->new_connection(pchan->data);
888 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300889 goto clean;
890
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300891 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300892
Ville Tervob62f3282011-02-10 22:38:50 -0300893 hci_conn_hold(conn->hcon);
894
Ville Tervob62f3282011-02-10 22:38:50 -0300895 bacpy(&bt_sk(sk)->src, conn->src);
896 bacpy(&bt_sk(sk)->dst, conn->dst);
897
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300898 bt_accept_enqueue(parent, sk);
899
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200900 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300901
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300902 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300903
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200904 __l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300905 parent->sk_data_ready(parent, 0);
906
Ville Tervob62f3282011-02-10 22:38:50 -0300907clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300908 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300909}
910
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200911static void l2cap_chan_ready(struct l2cap_chan *chan)
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300912{
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200913 struct sock *sk = chan->sk;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200914 struct sock *parent;
915
916 lock_sock(sk);
917
918 parent = bt_sk(sk)->parent;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300919
920 BT_DBG("sk %p, parent %p", sk, parent);
921
922 chan->conf_state = 0;
923 __clear_chan_timer(chan);
924
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200925 __l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300926 sk->sk_state_change(sk);
927
928 if (parent)
929 parent->sk_data_ready(parent, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200930
931 release_sock(sk);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300932}
933
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200934static void l2cap_conn_ready(struct l2cap_conn *conn)
935{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300936 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200937
938 BT_DBG("conn %p", conn);
939
Ville Tervob62f3282011-02-10 22:38:50 -0300940 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
941 l2cap_le_conn_ready(conn);
942
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300943 if (conn->hcon->out && conn->hcon->type == LE_LINK)
944 smp_conn_security(conn, conn->hcon->pending_sec_level);
945
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200946 mutex_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200947
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200948 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300949
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200950 l2cap_chan_lock(chan);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200951
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300952 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300953 if (smp_conn_security(conn, chan->sec_level))
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200954 l2cap_chan_ready(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300955
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300956 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200957 struct sock *sk = chan->sk;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300958 __clear_chan_timer(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200959 lock_sock(sk);
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +0200960 __l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200961 sk->sk_state_change(sk);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200962 release_sock(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300963
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300964 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300965 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200966
Andrei Emeltchenko6be36552012-02-22 17:11:56 +0200967 l2cap_chan_unlock(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200968 }
969
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200970 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200971}
972
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200973/* Notify sockets that we cannot guaranty reliability anymore */
974static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
975{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300976 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200977
978 BT_DBG("conn %p", conn);
979
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200980 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200981
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200982 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300983 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +0200984 __l2cap_chan_set_err(chan, err);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200985 }
986
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +0200987 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200988}
989
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200990static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200991{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200992 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200993 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200994
Marcel Holtmann984947d2009-02-06 23:35:19 +0100995 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100996 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100997
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200998 l2cap_conn_start(conn);
999}
1000
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001001static void l2cap_conn_del(struct hci_conn *hcon, int err)
1002{
1003 struct l2cap_conn *conn = hcon->l2cap_data;
1004 struct l2cap_chan *chan, *l;
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001005
1006 if (!conn)
1007 return;
1008
1009 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1010
1011 kfree_skb(conn->rx_skb);
1012
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001013 mutex_lock(&conn->chan_lock);
1014
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001015 /* Kill channels */
1016 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001017 l2cap_chan_lock(chan);
1018
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001019 l2cap_chan_del(chan, err);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001020
1021 l2cap_chan_unlock(chan);
1022
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001023 chan->ops->close(chan->data);
1024 }
1025
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001026 mutex_unlock(&conn->chan_lock);
1027
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001028 hci_chan_del(conn->hchan);
1029
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001030 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim127074b2012-01-30 18:26:29 -02001031 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001032
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001033 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim127074b2012-01-30 18:26:29 -02001034 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001035 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001036 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001037
1038 hcon->l2cap_data = NULL;
1039 kfree(conn);
1040}
1041
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001042static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001043{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001044 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1045 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001046
1047 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1048}
1049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1051{
Marcel Holtmann01394182006-07-03 10:02:46 +02001052 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001053 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054
Marcel Holtmann01394182006-07-03 10:02:46 +02001055 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 return conn;
1057
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001058 hchan = hci_chan_create(hcon);
1059 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001062 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1063 if (!conn) {
1064 hci_chan_del(hchan);
1065 return NULL;
1066 }
1067
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 hcon->l2cap_data = conn;
1069 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001070 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001072 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001073
Ville Tervoacd7d372011-02-10 22:38:49 -03001074 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1075 conn->mtu = hcon->hdev->le_mtu;
1076 else
1077 conn->mtu = hcon->hdev->acl_mtu;
1078
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 conn->src = &hcon->hdev->bdaddr;
1080 conn->dst = &hcon->dst;
1081
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001082 conn->feat_mask = 0;
1083
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 spin_lock_init(&conn->lock);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001085 mutex_init(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001086
1087 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001089 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001090 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001091 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001092 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001093
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001094 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return conn;
1097}
1098
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101/* Find socket with psm and source bdaddr.
1102 * Returns closest match.
1103 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001104static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001106 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001108 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001109
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001110 list_for_each_entry(c, &chan_list, global_l) {
1111 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001112
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001113 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 continue;
1115
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001116 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001118 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001119 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001120 return c;
1121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
1123 /* Closest match */
1124 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001125 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 }
1127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001129 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001130
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001131 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132}
1133
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001134int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001136 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 struct l2cap_conn *conn;
1139 struct hci_conn *hcon;
1140 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001141 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001142 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001144 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Andrei Emeltchenko097db762012-03-09 14:16:17 +02001145 __le16_to_cpu(chan->psm));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001147 hdev = hci_get_route(dst, src);
1148 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 return -EHOSTUNREACH;
1150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001151 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001153 l2cap_chan_lock(chan);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001154
1155 /* PSM must be odd and lsb of upper byte must be 0 */
1156 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1157 chan->chan_type != L2CAP_CHAN_RAW) {
1158 err = -EINVAL;
1159 goto done;
1160 }
1161
1162 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1163 err = -EINVAL;
1164 goto done;
1165 }
1166
1167 switch (chan->mode) {
1168 case L2CAP_MODE_BASIC:
1169 break;
1170 case L2CAP_MODE_ERTM:
1171 case L2CAP_MODE_STREAMING:
1172 if (!disable_ertm)
1173 break;
1174 /* fall through */
1175 default:
1176 err = -ENOTSUPP;
1177 goto done;
1178 }
1179
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001180 lock_sock(sk);
1181
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001182 switch (sk->sk_state) {
1183 case BT_CONNECT:
1184 case BT_CONNECT2:
1185 case BT_CONFIG:
1186 /* Already connecting */
1187 err = 0;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001188 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001189 goto done;
1190
1191 case BT_CONNECTED:
1192 /* Already connected */
1193 err = -EISCONN;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001194 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001195 goto done;
1196
1197 case BT_OPEN:
1198 case BT_BOUND:
1199 /* Can connect */
1200 break;
1201
1202 default:
1203 err = -EBADFD;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001204 release_sock(sk);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001205 goto done;
1206 }
1207
1208 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001209 bacpy(&bt_sk(sk)->dst, dst);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001210
1211 release_sock(sk);
1212
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001213 chan->psm = psm;
1214 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001216 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001217
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001218 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001219 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001220 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001221 else
1222 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001223 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001224
Ville Tervo30e76272011-02-22 16:10:53 -03001225 if (IS_ERR(hcon)) {
1226 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
1230 conn = l2cap_conn_add(hcon, 0);
1231 if (!conn) {
1232 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001233 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 goto done;
1235 }
1236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 /* Update source addr of the socket */
1238 bacpy(src, conn->src);
1239
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001240 l2cap_chan_unlock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001241 l2cap_chan_add(conn, chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001242 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001243
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001244 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001245 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001248 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001249 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001250 if (l2cap_chan_check_security(chan))
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001251 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001252 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001253 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 }
1255
Ville Tervo30e76272011-02-22 16:10:53 -03001256 err = 0;
1257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001259 l2cap_chan_unlock(chan);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001260 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 hci_dev_put(hdev);
1262 return err;
1263}
1264
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001265int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001266{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001267 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001268 DECLARE_WAITQUEUE(wait, current);
1269 int err = 0;
1270 int timeo = HZ/5;
1271
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001272 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001273 set_current_state(TASK_INTERRUPTIBLE);
1274 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001275 if (!timeo)
1276 timeo = HZ/5;
1277
1278 if (signal_pending(current)) {
1279 err = sock_intr_errno(timeo);
1280 break;
1281 }
1282
1283 release_sock(sk);
1284 timeo = schedule_timeout(timeo);
1285 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001286 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001287
1288 err = sock_error(sk);
1289 if (err)
1290 break;
1291 }
1292 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001293 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001294 return err;
1295}
1296
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001297static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001298{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001299 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1300 monitor_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001301
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001302 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001303
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001304 l2cap_chan_lock(chan);
1305
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001306 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001307 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001308 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001309 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001310 return;
1311 }
1312
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001313 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001314 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001315
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001316 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001317 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001318 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001319}
1320
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001321static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001322{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001323 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1324 retrans_timer.work);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001325
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001326 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001327
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001328 l2cap_chan_lock(chan);
1329
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001330 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001331 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001332
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001333 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001334
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001335 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02001336
1337 l2cap_chan_unlock(chan);
Andrei Emeltchenko8d7e1c72012-03-23 09:42:15 +02001338 l2cap_chan_put(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001339}
1340
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001341static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001342{
1343 struct sk_buff *skb;
1344
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001345 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001346 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001347 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001348 break;
1349
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001350 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001351 kfree_skb(skb);
1352
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001353 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001354 }
1355
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001356 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001357 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001358}
1359
Szymon Janc67c9e842011-07-28 16:24:33 +02001360static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001361{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001362 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001363 u32 control;
1364 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001365
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001366 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001367 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001368 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001369 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001370
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001371 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001372 fcs = crc16(0, (u8 *)skb->data,
1373 skb->len - L2CAP_FCS_SIZE);
1374 put_unaligned_le16(fcs,
1375 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001376 }
1377
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001378 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001379
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001380 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001381 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001382}
1383
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001384static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001385{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001386 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001387 u16 fcs;
1388 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001389
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001390 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001391 if (!skb)
1392 return;
1393
Szymon Jancd1726b62011-11-16 09:32:20 +01001394 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001395 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001396 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001397
Szymon Jancd1726b62011-11-16 09:32:20 +01001398 skb = skb_queue_next(&chan->tx_q, skb);
1399 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001400
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001401 if (chan->remote_max_tx &&
1402 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001403 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001404 return;
1405 }
1406
1407 tx_skb = skb_clone(skb, GFP_ATOMIC);
1408 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001409
1410 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001411 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001412
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001413 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001414 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001415
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001416 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001417 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001418
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001419 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001420
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001421 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001422 fcs = crc16(0, (u8 *)tx_skb->data,
1423 tx_skb->len - L2CAP_FCS_SIZE);
1424 put_unaligned_le16(fcs,
1425 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001426 }
1427
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001428 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001429}
1430
Szymon Janc67c9e842011-07-28 16:24:33 +02001431static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001432{
1433 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001434 u16 fcs;
1435 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001436 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001437
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001438 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001439 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001440
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001441 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001442
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001443 if (chan->remote_max_tx &&
1444 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001445 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001446 break;
1447 }
1448
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001449 tx_skb = skb_clone(skb, GFP_ATOMIC);
1450
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001451 bt_cb(skb)->retries++;
1452
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001453 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001454 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001455
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001456 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001457 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001458
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001459 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001460 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001461
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001462 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001463
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001464 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001465 fcs = crc16(0, (u8 *)skb->data,
1466 tx_skb->len - L2CAP_FCS_SIZE);
1467 put_unaligned_le16(fcs, skb->data +
1468 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001469 }
1470
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001471 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001472
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001473 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001474
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001475 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001476
1477 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001478
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001479 if (bt_cb(skb)->retries == 1) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001480 chan->unacked_frames++;
Szymon Janc930fa4a2012-02-07 15:43:02 +01001481
1482 if (!nsent++)
1483 __clear_ack_timer(chan);
Szymon Janc8ed7a0a2012-02-07 15:43:01 +01001484 }
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301485
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001486 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001487
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001488 if (skb_queue_is_last(&chan->tx_q, skb))
1489 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001490 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001491 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001492 }
1493
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001494 return nsent;
1495}
1496
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001497static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001498{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001499 int ret;
1500
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001501 if (!skb_queue_empty(&chan->tx_q))
1502 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001503
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001504 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001505 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001506 return ret;
1507}
1508
Szymon Jancb17e73b2012-01-11 10:59:47 +01001509static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001510{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001511 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001512
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001513 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001514
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001515 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001516 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001517 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001518 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001519 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001520 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001521
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001522 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001523 return;
1524
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001525 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001526 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001527}
1528
Szymon Jancb17e73b2012-01-11 10:59:47 +01001529static void l2cap_send_ack(struct l2cap_chan *chan)
1530{
1531 __clear_ack_timer(chan);
1532 __l2cap_send_ack(chan);
1533}
1534
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001535static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001536{
1537 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001538 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001539
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001540 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001541 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001542
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001543 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001544 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001545
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001546 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001547}
1548
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001549static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
1550 struct msghdr *msg, int len,
1551 int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001553 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001554 struct sk_buff **frag;
1555 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001557 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001558 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
1560 sent += count;
1561 len -= count;
1562
1563 /* Continuation fragments (no L2CAP header) */
1564 frag = &skb_shinfo(skb)->frag_list;
1565 while (len) {
1566 count = min_t(unsigned int, conn->mtu, len);
1567
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001568 *frag = chan->ops->alloc_skb(chan, count,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001569 msg->msg_flags & MSG_DONTWAIT,
1570 &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001571
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001573 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001574 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1575 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001577 (*frag)->priority = skb->priority;
1578
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579 sent += count;
1580 len -= count;
1581
1582 frag = &(*frag)->next;
1583 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
1585 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001586}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001588static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1589 struct msghdr *msg, size_t len,
1590 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001591{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001592 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001593 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001594 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001595 struct l2cap_hdr *lh;
1596
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001597 BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001598
1599 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001600
1601 skb = chan->ops->alloc_skb(chan, count + hlen,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001602 msg->msg_flags & MSG_DONTWAIT, &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001603
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001604 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001605 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001606
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001607 skb->priority = priority;
1608
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001609 /* Create L2CAP header */
1610 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001611 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001612 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko097db762012-03-09 14:16:17 +02001613 put_unaligned(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001614
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001615 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001616 if (unlikely(err < 0)) {
1617 kfree_skb(skb);
1618 return ERR_PTR(err);
1619 }
1620 return skb;
1621}
1622
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001623static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1624 struct msghdr *msg, size_t len,
1625 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001626{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001627 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001628 struct sk_buff *skb;
1629 int err, count, hlen = L2CAP_HDR_SIZE;
1630 struct l2cap_hdr *lh;
1631
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001632 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001633
1634 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001635
1636 skb = chan->ops->alloc_skb(chan, count + hlen,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001637 msg->msg_flags & MSG_DONTWAIT, &err);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001638
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001639 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001640 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001641
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001642 skb->priority = priority;
1643
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001644 /* Create L2CAP header */
1645 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001646 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001647 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1648
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001649 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001650 if (unlikely(err < 0)) {
1651 kfree_skb(skb);
1652 return ERR_PTR(err);
1653 }
1654 return skb;
1655}
1656
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001657static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1658 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001659 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001660{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001661 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001662 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001663 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001664 struct l2cap_hdr *lh;
1665
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001666 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001667
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001668 if (!conn)
1669 return ERR_PTR(-ENOTCONN);
1670
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001671 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1672 hlen = L2CAP_EXT_HDR_SIZE;
1673 else
1674 hlen = L2CAP_ENH_HDR_SIZE;
1675
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001676 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001677 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001678
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001679 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001680 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001681
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001682 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001683
1684 skb = chan->ops->alloc_skb(chan, count + hlen,
1685 msg->msg_flags & MSG_DONTWAIT, &err);
1686
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001687 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001688 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001689
1690 /* Create L2CAP header */
1691 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001692 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001693 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001694
1695 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1696
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001697 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001698 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001699
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001700 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001701 if (unlikely(err < 0)) {
1702 kfree_skb(skb);
1703 return ERR_PTR(err);
1704 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001705
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001706 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001707 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001708
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001709 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001710 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711}
1712
Szymon Janc67c9e842011-07-28 16:24:33 +02001713static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001714{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001715 struct sk_buff *skb;
1716 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001717 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001718 size_t size = 0;
1719
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001720 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001721 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001722 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001723 if (IS_ERR(skb))
1724 return PTR_ERR(skb);
1725
1726 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001727 len -= chan->remote_mps;
1728 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001729
1730 while (len > 0) {
1731 size_t buflen;
1732
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001733 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001734 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001735 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001736 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001737 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001738 buflen = len;
1739 }
1740
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001741 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001742 if (IS_ERR(skb)) {
1743 skb_queue_purge(&sar_queue);
1744 return PTR_ERR(skb);
1745 }
1746
1747 __skb_queue_tail(&sar_queue, skb);
1748 len -= buflen;
1749 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001750 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001751 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1752 if (chan->tx_send_head == NULL)
1753 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001754
1755 return size;
1756}
1757
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001758int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1759 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001760{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001761 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001762 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001763 int err;
1764
1765 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001766 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001767 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001768 if (IS_ERR(skb))
1769 return PTR_ERR(skb);
1770
1771 l2cap_do_send(chan, skb);
1772 return len;
1773 }
1774
1775 switch (chan->mode) {
1776 case L2CAP_MODE_BASIC:
1777 /* Check outgoing MTU */
1778 if (len > chan->omtu)
1779 return -EMSGSIZE;
1780
1781 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001782 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001783 if (IS_ERR(skb))
1784 return PTR_ERR(skb);
1785
1786 l2cap_do_send(chan, skb);
1787 err = len;
1788 break;
1789
1790 case L2CAP_MODE_ERTM:
1791 case L2CAP_MODE_STREAMING:
1792 /* Entire SDU fits into one PDU */
1793 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001794 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001795 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1796 0);
1797 if (IS_ERR(skb))
1798 return PTR_ERR(skb);
1799
1800 __skb_queue_tail(&chan->tx_q, skb);
1801
1802 if (chan->tx_send_head == NULL)
1803 chan->tx_send_head = skb;
1804
1805 } else {
1806 /* Segment SDU into multiples PDUs */
1807 err = l2cap_sar_segment_sdu(chan, msg, len);
1808 if (err < 0)
1809 return err;
1810 }
1811
1812 if (chan->mode == L2CAP_MODE_STREAMING) {
1813 l2cap_streaming_send(chan);
1814 err = len;
1815 break;
1816 }
1817
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001818 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1819 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001820 err = len;
1821 break;
1822 }
1823
1824 err = l2cap_ertm_send(chan);
1825 if (err >= 0)
1826 err = len;
1827
1828 break;
1829
1830 default:
1831 BT_DBG("bad state %1.1x", chan->mode);
1832 err = -EBADFD;
1833 }
1834
1835 return err;
1836}
1837
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838/* Copy frame to all raw sockets on that connection */
1839static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1840{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001842 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844 BT_DBG("conn %p", conn);
1845
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001846 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001847
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001848 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001849 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001850 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 continue;
1852
1853 /* Don't send frame to the socket it came from */
1854 if (skb->sk == sk)
1855 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001856 nskb = skb_clone(skb, GFP_ATOMIC);
1857 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 continue;
1859
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001860 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 kfree_skb(nskb);
1862 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001863
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02001864 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865}
1866
1867/* ---- L2CAP signalling commands ---- */
1868static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1869 u8 code, u8 ident, u16 dlen, void *data)
1870{
1871 struct sk_buff *skb, **frag;
1872 struct l2cap_cmd_hdr *cmd;
1873 struct l2cap_hdr *lh;
1874 int len, count;
1875
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001876 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1877 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
1879 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1880 count = min_t(unsigned int, conn->mtu, len);
1881
1882 skb = bt_skb_alloc(count, GFP_ATOMIC);
1883 if (!skb)
1884 return NULL;
1885
1886 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001887 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001888
1889 if (conn->hcon->type == LE_LINK)
1890 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1891 else
1892 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893
1894 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1895 cmd->code = code;
1896 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001897 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898
1899 if (dlen) {
1900 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1901 memcpy(skb_put(skb, count), data, count);
1902 data += count;
1903 }
1904
1905 len -= skb->len;
1906
1907 /* Continuation fragments (no L2CAP header) */
1908 frag = &skb_shinfo(skb)->frag_list;
1909 while (len) {
1910 count = min_t(unsigned int, conn->mtu, len);
1911
1912 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1913 if (!*frag)
1914 goto fail;
1915
1916 memcpy(skb_put(*frag, count), data, count);
1917
1918 len -= count;
1919 data += count;
1920
1921 frag = &(*frag)->next;
1922 }
1923
1924 return skb;
1925
1926fail:
1927 kfree_skb(skb);
1928 return NULL;
1929}
1930
1931static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1932{
1933 struct l2cap_conf_opt *opt = *ptr;
1934 int len;
1935
1936 len = L2CAP_CONF_OPT_SIZE + opt->len;
1937 *ptr += len;
1938
1939 *type = opt->type;
1940 *olen = opt->len;
1941
1942 switch (opt->len) {
1943 case 1:
1944 *val = *((u8 *) opt->val);
1945 break;
1946
1947 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001948 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 break;
1950
1951 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001952 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 break;
1954
1955 default:
1956 *val = (unsigned long) opt->val;
1957 break;
1958 }
1959
1960 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1961 return len;
1962}
1963
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1965{
1966 struct l2cap_conf_opt *opt = *ptr;
1967
1968 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1969
1970 opt->type = type;
1971 opt->len = len;
1972
1973 switch (len) {
1974 case 1:
1975 *((u8 *) opt->val) = val;
1976 break;
1977
1978 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001979 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 break;
1981
1982 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001983 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 break;
1985
1986 default:
1987 memcpy(opt->val, (void *) val, len);
1988 break;
1989 }
1990
1991 *ptr += L2CAP_CONF_OPT_SIZE + len;
1992}
1993
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001994static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1995{
1996 struct l2cap_conf_efs efs;
1997
Szymon Janc1ec918c2011-11-16 09:32:21 +01001998 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001999 case L2CAP_MODE_ERTM:
2000 efs.id = chan->local_id;
2001 efs.stype = chan->local_stype;
2002 efs.msdu = cpu_to_le16(chan->local_msdu);
2003 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2004 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
2005 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
2006 break;
2007
2008 case L2CAP_MODE_STREAMING:
2009 efs.id = 1;
2010 efs.stype = L2CAP_SERV_BESTEFFORT;
2011 efs.msdu = cpu_to_le16(chan->local_msdu);
2012 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
2013 efs.acc_lat = 0;
2014 efs.flush_to = 0;
2015 break;
2016
2017 default:
2018 return;
2019 }
2020
2021 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
2022 (unsigned long) &efs);
2023}
2024
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002025static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002026{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002027 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2028 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002029
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02002030 BT_DBG("chan %p", chan);
2031
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002032 l2cap_chan_lock(chan);
2033
Szymon Jancb17e73b2012-01-11 10:59:47 +01002034 __l2cap_send_ack(chan);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002035
2036 l2cap_chan_unlock(chan);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002037
2038 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002039}
2040
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002041static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002042{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002043 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002044 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002045 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002046 chan->num_acked = 0;
2047 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002048
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002049 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2050 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2051 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002052
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002053 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002054
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002055 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002056}
2057
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002058static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2059{
2060 switch (mode) {
2061 case L2CAP_MODE_STREAMING:
2062 case L2CAP_MODE_ERTM:
2063 if (l2cap_mode_supported(mode, remote_feat_mask))
2064 return mode;
2065 /* fall through */
2066 default:
2067 return L2CAP_MODE_BASIC;
2068 }
2069}
2070
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002071static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2072{
2073 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2074}
2075
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002076static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2077{
2078 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2079}
2080
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002081static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2082{
2083 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002084 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002085 /* use extended control field */
2086 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002087 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2088 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002089 chan->tx_win = min_t(u16, chan->tx_win,
2090 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002091 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2092 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002093}
2094
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002095static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002098 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002099 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002100 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002102 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002104 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002105 goto done;
2106
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002107 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002108 case L2CAP_MODE_STREAMING:
2109 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002110 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002111 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002112
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002113 if (__l2cap_efs_supported(chan))
2114 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2115
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002116 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002117 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002118 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002119 break;
2120 }
2121
2122done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002123 if (chan->imtu != L2CAP_DEFAULT_MTU)
2124 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002125
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002126 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002127 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002128 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2129 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002130 break;
2131
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002132 rfc.mode = L2CAP_MODE_BASIC;
2133 rfc.txwin_size = 0;
2134 rfc.max_transmit = 0;
2135 rfc.retrans_timeout = 0;
2136 rfc.monitor_timeout = 0;
2137 rfc.max_pdu_size = 0;
2138
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002139 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2140 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002141 break;
2142
2143 case L2CAP_MODE_ERTM:
2144 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002145 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002146 rfc.retrans_timeout = 0;
2147 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002148
2149 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2150 L2CAP_EXT_HDR_SIZE -
2151 L2CAP_SDULEN_SIZE -
2152 L2CAP_FCS_SIZE);
2153 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002154
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002155 l2cap_txwin_setup(chan);
2156
2157 rfc.txwin_size = min_t(u16, chan->tx_win,
2158 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002159
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002160 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2161 (unsigned long) &rfc);
2162
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002163 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2164 l2cap_add_opt_efs(&ptr, chan);
2165
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002166 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002167 break;
2168
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002169 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002170 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002171 chan->fcs = L2CAP_FCS_NONE;
2172 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002173 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002174
2175 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2176 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2177 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002178 break;
2179
2180 case L2CAP_MODE_STREAMING:
2181 rfc.mode = L2CAP_MODE_STREAMING;
2182 rfc.txwin_size = 0;
2183 rfc.max_transmit = 0;
2184 rfc.retrans_timeout = 0;
2185 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002186
2187 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2188 L2CAP_EXT_HDR_SIZE -
2189 L2CAP_SDULEN_SIZE -
2190 L2CAP_FCS_SIZE);
2191 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002192
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002193 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2194 (unsigned long) &rfc);
2195
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002196 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2197 l2cap_add_opt_efs(&ptr, chan);
2198
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002199 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002200 break;
2201
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002202 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002203 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002204 chan->fcs = L2CAP_FCS_NONE;
2205 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002206 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002207 break;
2208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002210 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002211 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
2213 return ptr - data;
2214}
2215
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002216static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002218 struct l2cap_conf_rsp *rsp = data;
2219 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002220 void *req = chan->conf_req;
2221 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002222 int type, hint, olen;
2223 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002224 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002225 struct l2cap_conf_efs efs;
2226 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002227 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002228 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002229 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002231 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002232
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002233 while (len >= L2CAP_CONF_OPT_SIZE) {
2234 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002236 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002237 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002238
2239 switch (type) {
2240 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002241 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002242 break;
2243
2244 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002245 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002246 break;
2247
2248 case L2CAP_CONF_QOS:
2249 break;
2250
Marcel Holtmann6464f352007-10-20 13:39:51 +02002251 case L2CAP_CONF_RFC:
2252 if (olen == sizeof(rfc))
2253 memcpy(&rfc, (void *) val, olen);
2254 break;
2255
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002256 case L2CAP_CONF_FCS:
2257 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002258 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002259 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002260
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002261 case L2CAP_CONF_EFS:
2262 remote_efs = 1;
2263 if (olen == sizeof(efs))
2264 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002265 break;
2266
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002267 case L2CAP_CONF_EWS:
2268 if (!enable_hs)
2269 return -ECONNREFUSED;
2270
2271 set_bit(FLAG_EXT_CTRL, &chan->flags);
2272 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002273 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002274 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002275 break;
2276
2277 default:
2278 if (hint)
2279 break;
2280
2281 result = L2CAP_CONF_UNKNOWN;
2282 *((u8 *) ptr++) = type;
2283 break;
2284 }
2285 }
2286
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002287 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002288 goto done;
2289
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002290 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002291 case L2CAP_MODE_STREAMING:
2292 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002293 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002294 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002295 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002296 break;
2297 }
2298
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002299 if (remote_efs) {
2300 if (__l2cap_efs_supported(chan))
2301 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2302 else
2303 return -ECONNREFUSED;
2304 }
2305
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002306 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002307 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002308
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002309 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002310 }
2311
2312done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002313 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002314 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002315 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002316
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002317 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002318 return -ECONNREFUSED;
2319
2320 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2321 sizeof(rfc), (unsigned long) &rfc);
2322 }
2323
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002324 if (result == L2CAP_CONF_SUCCESS) {
2325 /* Configure output options and let the other side know
2326 * which ones we don't like. */
2327
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002328 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2329 result = L2CAP_CONF_UNACCEPT;
2330 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002331 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002332 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002333 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002334 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002335
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002336 if (remote_efs) {
2337 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2338 efs.stype != L2CAP_SERV_NOTRAFIC &&
2339 efs.stype != chan->local_stype) {
2340
2341 result = L2CAP_CONF_UNACCEPT;
2342
2343 if (chan->num_conf_req >= 1)
2344 return -ECONNREFUSED;
2345
2346 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002347 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002348 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002349 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002350 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002351 result = L2CAP_CONF_PENDING;
2352 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002353 }
2354 }
2355
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002356 switch (rfc.mode) {
2357 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002358 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002359 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002360 break;
2361
2362 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002363 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2364 chan->remote_tx_win = rfc.txwin_size;
2365 else
2366 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2367
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002368 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002369
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002370 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2371 chan->conn->mtu -
2372 L2CAP_EXT_HDR_SIZE -
2373 L2CAP_SDULEN_SIZE -
2374 L2CAP_FCS_SIZE);
2375 rfc.max_pdu_size = cpu_to_le16(size);
2376 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002377
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002378 rfc.retrans_timeout =
Andrei Emeltchenko4fd21a82012-03-12 12:13:10 +02002379 __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002380 rfc.monitor_timeout =
Andrei Emeltchenko4fd21a82012-03-12 12:13:10 +02002381 __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002382
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002383 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002384
2385 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2386 sizeof(rfc), (unsigned long) &rfc);
2387
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002388 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2389 chan->remote_id = efs.id;
2390 chan->remote_stype = efs.stype;
2391 chan->remote_msdu = le16_to_cpu(efs.msdu);
2392 chan->remote_flush_to =
2393 le32_to_cpu(efs.flush_to);
2394 chan->remote_acc_lat =
2395 le32_to_cpu(efs.acc_lat);
2396 chan->remote_sdu_itime =
2397 le32_to_cpu(efs.sdu_itime);
2398 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2399 sizeof(efs), (unsigned long) &efs);
2400 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002401 break;
2402
2403 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002404 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2405 chan->conn->mtu -
2406 L2CAP_EXT_HDR_SIZE -
2407 L2CAP_SDULEN_SIZE -
2408 L2CAP_FCS_SIZE);
2409 rfc.max_pdu_size = cpu_to_le16(size);
2410 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002411
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002412 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002413
2414 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2415 sizeof(rfc), (unsigned long) &rfc);
2416
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002417 break;
2418
2419 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002420 result = L2CAP_CONF_UNACCEPT;
2421
2422 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002423 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002424 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002425
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002426 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002427 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002428 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002429 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002430 rsp->result = cpu_to_le16(result);
2431 rsp->flags = cpu_to_le16(0x0000);
2432
2433 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434}
2435
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002436static 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 -03002437{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002438 struct l2cap_conf_req *req = data;
2439 void *ptr = req->data;
2440 int type, olen;
2441 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002442 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002443 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002444
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002445 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002446
2447 while (len >= L2CAP_CONF_OPT_SIZE) {
2448 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2449
2450 switch (type) {
2451 case L2CAP_CONF_MTU:
2452 if (val < L2CAP_DEFAULT_MIN_MTU) {
2453 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002454 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002455 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002456 chan->imtu = val;
2457 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002458 break;
2459
2460 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002461 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002462 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002463 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002464 break;
2465
2466 case L2CAP_CONF_RFC:
2467 if (olen == sizeof(rfc))
2468 memcpy(&rfc, (void *)val, olen);
2469
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002470 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002471 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002472 return -ECONNREFUSED;
2473
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002474 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002475
2476 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2477 sizeof(rfc), (unsigned long) &rfc);
2478 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002479
2480 case L2CAP_CONF_EWS:
2481 chan->tx_win = min_t(u16, val,
2482 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002483 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2484 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002485 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002486
2487 case L2CAP_CONF_EFS:
2488 if (olen == sizeof(efs))
2489 memcpy(&efs, (void *)val, olen);
2490
2491 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2492 efs.stype != L2CAP_SERV_NOTRAFIC &&
2493 efs.stype != chan->local_stype)
2494 return -ECONNREFUSED;
2495
2496 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2497 sizeof(efs), (unsigned long) &efs);
2498 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002499 }
2500 }
2501
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002502 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002503 return -ECONNREFUSED;
2504
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002505 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002506
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002507 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002508 switch (rfc.mode) {
2509 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002510 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2511 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2512 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002513
2514 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2515 chan->local_msdu = le16_to_cpu(efs.msdu);
2516 chan->local_sdu_itime =
2517 le32_to_cpu(efs.sdu_itime);
2518 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2519 chan->local_flush_to =
2520 le32_to_cpu(efs.flush_to);
2521 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002522 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002523
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002524 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002525 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002526 }
2527 }
2528
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002529 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002530 req->flags = cpu_to_le16(0x0000);
2531
2532 return ptr - data;
2533}
2534
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002535static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536{
2537 struct l2cap_conf_rsp *rsp = data;
2538 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002540 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002541
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002542 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002543 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002544 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545
2546 return ptr - data;
2547}
2548
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002549void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002550{
2551 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002552 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002553 u8 buf[128];
2554
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002555 rsp.scid = cpu_to_le16(chan->dcid);
2556 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002557 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2558 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2559 l2cap_send_cmd(conn, chan->ident,
2560 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2561
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002562 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002563 return;
2564
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002565 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2566 l2cap_build_conf_req(chan, buf), buf);
2567 chan->num_conf_req++;
2568}
2569
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002570static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002571{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002572 int type, olen;
2573 unsigned long val;
2574 struct l2cap_conf_rfc rfc;
2575
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002576 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002577
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002578 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002579 return;
2580
2581 while (len >= L2CAP_CONF_OPT_SIZE) {
2582 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2583
2584 switch (type) {
2585 case L2CAP_CONF_RFC:
2586 if (olen == sizeof(rfc))
2587 memcpy(&rfc, (void *)val, olen);
2588 goto done;
2589 }
2590 }
2591
Mat Martineau36e999a2011-12-08 17:23:21 -08002592 /* Use sane default values in case a misbehaving remote device
2593 * did not send an RFC option.
2594 */
2595 rfc.mode = chan->mode;
2596 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2597 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2598 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2599
2600 BT_ERR("Expected RFC option was not found, using defaults");
2601
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002602done:
2603 switch (rfc.mode) {
2604 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002605 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2606 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2607 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002608 break;
2609 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002610 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002611 }
2612}
2613
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002614static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2615{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002616 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002617
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002618 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002619 return 0;
2620
2621 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2622 cmd->ident == conn->info_ident) {
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02002623 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002624
2625 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002626 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002627
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002628 l2cap_conn_start(conn);
2629 }
2630
2631 return 0;
2632}
2633
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2635{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2637 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002638 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002639 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002640 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641
2642 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002643 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644
Andrei Emeltchenko097db762012-03-09 14:16:17 +02002645 BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646
2647 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002648 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2649 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 result = L2CAP_CR_BAD_PSM;
2651 goto sendresp;
2652 }
2653
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002654 parent = pchan->sk;
2655
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002656 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002657 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002658
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002659 /* Check if the ACL is secure enough (if not SDP) */
2660 if (psm != cpu_to_le16(0x0001) &&
2661 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002662 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002663 result = L2CAP_CR_SEC_BLOCK;
2664 goto response;
2665 }
2666
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 result = L2CAP_CR_NO_MEM;
2668
2669 /* Check for backlog size */
2670 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002671 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 goto response;
2673 }
2674
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002675 chan = pchan->ops->new_connection(pchan->data);
2676 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 goto response;
2678
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002679 sk = chan->sk;
2680
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002682 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002684 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 goto response;
2686 }
2687
2688 hci_conn_hold(conn->hcon);
2689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 bacpy(&bt_sk(sk)->src, conn->src);
2691 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002692 chan->psm = psm;
2693 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002695 bt_accept_enqueue(parent, sk);
2696
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002697 __l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002698
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002699 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002701 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002703 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
Marcel Holtmann984947d2009-02-06 23:35:19 +01002705 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002706 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002707 if (bt_sk(sk)->defer_setup) {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002708 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002709 result = L2CAP_CR_PEND;
2710 status = L2CAP_CS_AUTHOR_PEND;
2711 parent->sk_data_ready(parent, 0);
2712 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002713 __l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002714 result = L2CAP_CR_SUCCESS;
2715 status = L2CAP_CS_NO_INFO;
2716 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002717 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002718 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002719 result = L2CAP_CR_PEND;
2720 status = L2CAP_CS_AUTHEN_PEND;
2721 }
2722 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02002723 __l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002724 result = L2CAP_CR_PEND;
2725 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 }
2727
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002729 release_sock(parent);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002730 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731
2732sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002733 rsp.scid = cpu_to_le16(scid);
2734 rsp.dcid = cpu_to_le16(dcid);
2735 rsp.result = cpu_to_le16(result);
2736 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002738
2739 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2740 struct l2cap_info_req info;
2741 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2742
2743 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2744 conn->info_ident = l2cap_get_ident(conn);
2745
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08002746 schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002747
2748 l2cap_send_cmd(conn, conn->info_ident,
2749 L2CAP_INFO_REQ, sizeof(info), &info);
2750 }
2751
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002752 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002753 result == L2CAP_CR_SUCCESS) {
2754 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002755 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002756 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002757 l2cap_build_conf_req(chan, buf), buf);
2758 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002759 }
2760
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 return 0;
2762}
2763
2764static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2765{
2766 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2767 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002768 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 u8 req[128];
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002770 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771
2772 scid = __le16_to_cpu(rsp->scid);
2773 dcid = __le16_to_cpu(rsp->dcid);
2774 result = __le16_to_cpu(rsp->result);
2775 status = __le16_to_cpu(rsp->status);
2776
Andrei Emeltchenko1b009c92012-02-21 12:54:54 +02002777 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
2778 dcid, scid, result, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002780 mutex_lock(&conn->chan_lock);
2781
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 if (scid) {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002783 chan = __l2cap_get_chan_by_scid(conn, scid);
2784 if (!chan) {
2785 err = -EFAULT;
2786 goto unlock;
2787 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 } else {
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002789 chan = __l2cap_get_chan_by_ident(conn, cmd->ident);
2790 if (!chan) {
2791 err = -EFAULT;
2792 goto unlock;
2793 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 }
2795
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002796 err = 0;
2797
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002798 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002799
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 switch (result) {
2801 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002802 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002803 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002804 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002805 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002806
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002807 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002808 break;
2809
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002811 l2cap_build_conf_req(chan, req), req);
2812 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 break;
2814
2815 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002816 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 break;
2818
2819 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002820 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 break;
2822 }
2823
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002824 l2cap_chan_unlock(chan);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02002825
2826unlock:
2827 mutex_unlock(&conn->chan_lock);
2828
2829 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830}
2831
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002832static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002833{
2834 /* FCS is enabled only in ERTM or streaming mode, if one or both
2835 * sides request it.
2836 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002837 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002838 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002839 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002840 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002841}
2842
Al Viro88219a02007-07-29 00:17:25 -07002843static 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 -07002844{
2845 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2846 u16 dcid, flags;
2847 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002848 struct l2cap_chan *chan;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002849 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
2851 dcid = __le16_to_cpu(req->dcid);
2852 flags = __le16_to_cpu(req->flags);
2853
2854 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2855
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002856 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002857 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 return -ENOENT;
2859
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002860 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002861
David S. Miller033b1142011-07-21 13:38:42 -07002862 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002863 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002864
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002865 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2866 rej.scid = cpu_to_le16(chan->scid);
2867 rej.dcid = cpu_to_le16(chan->dcid);
2868
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002869 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2870 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002871 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002872 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002873
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002874 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002875 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002876 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002877 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002878 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002879 L2CAP_CONF_REJECT, flags), rsp);
2880 goto unlock;
2881 }
2882
2883 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002884 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2885 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886
2887 if (flags & 0x0001) {
2888 /* Incomplete config. Send empty response. */
2889 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002890 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002891 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002892 goto unlock;
2893 }
2894
2895 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002896 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002897 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002898 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002900 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002902 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002903 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002904
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002905 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002906 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002907
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002908 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002909 goto unlock;
2910
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002911 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002912 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002913
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002914 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002915
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002916 chan->next_tx_seq = 0;
2917 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002918 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002919 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002920 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002921
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02002922 l2cap_chan_ready(chan);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002923 goto unlock;
2924 }
2925
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002926 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002927 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002929 l2cap_build_conf_req(chan, buf), buf);
2930 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 }
2932
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002933 /* Got Conf Rsp PENDING from remote side and asume we sent
2934 Conf Rsp PENDING in the code above */
2935 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2936 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2937
2938 /* check compatibility */
2939
2940 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2941 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2942
2943 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002944 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002945 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2946 }
2947
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948unlock:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002949 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950 return 0;
2951}
2952
2953static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2954{
2955 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2956 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002957 struct l2cap_chan *chan;
Andrei Emeltchenko61386cb2012-03-12 12:13:07 +02002958 int len = le16_to_cpu(cmd->len) - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
2960 scid = __le16_to_cpu(rsp->scid);
2961 flags = __le16_to_cpu(rsp->flags);
2962 result = __le16_to_cpu(rsp->result);
2963
Andrei Emeltchenko61386cb2012-03-12 12:13:07 +02002964 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x len %d", scid, flags,
2965 result, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002967 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002968 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 return 0;
2970
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02002971 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002972
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 switch (result) {
2974 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002975 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002976 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 break;
2978
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002979 case L2CAP_CONF_PENDING:
2980 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2981
2982 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2983 char buf[64];
2984
2985 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2986 buf, &result);
2987 if (len < 0) {
2988 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2989 goto done;
2990 }
2991
2992 /* check compatibility */
2993
2994 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2995 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2996
2997 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002998 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002999 L2CAP_CONF_SUCCESS, 0x0000), buf);
3000 }
3001 goto done;
3002
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003004 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003005 char req[64];
3006
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003007 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003008 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02003009 goto done;
3010 }
3011
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003012 /* throw out any old stored conf requests */
3013 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03003014 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
3015 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003016 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003017 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003018 goto done;
3019 }
3020
3021 l2cap_send_cmd(conn, l2cap_get_ident(conn),
3022 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03003023 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03003024 if (result != L2CAP_CONF_SUCCESS)
3025 goto done;
3026 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 }
3028
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09003029 default:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003030 l2cap_chan_set_err(chan, ECONNRESET);
Andrei Emeltchenko2e0052e2012-02-21 12:54:58 +02003031
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08003032 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003033 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 goto done;
3035 }
3036
3037 if (flags & 0x01)
3038 goto done;
3039
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003040 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003042 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003043 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003044
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003045 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003046 chan->next_tx_seq = 0;
3047 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003048 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003049 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003050 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003051
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02003052 l2cap_chan_ready(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 }
3054
3055done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003056 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 return 0;
3058}
3059
3060static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3061{
3062 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3063 struct l2cap_disconn_rsp rsp;
3064 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003065 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 struct sock *sk;
3067
3068 scid = __le16_to_cpu(req->scid);
3069 dcid = __le16_to_cpu(req->dcid);
3070
3071 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3072
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003073 mutex_lock(&conn->chan_lock);
3074
3075 chan = __l2cap_get_chan_by_scid(conn, dcid);
3076 if (!chan) {
3077 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003081 l2cap_chan_lock(chan);
3082
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003083 sk = chan->sk;
3084
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003085 rsp.dcid = cpu_to_le16(chan->scid);
3086 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3088
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003089 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090 sk->sk_shutdown = SHUTDOWN_MASK;
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003091 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003093 l2cap_chan_del(chan, ECONNRESET);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003094
3095 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003097 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003098
3099 mutex_unlock(&conn->chan_lock);
3100
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 return 0;
3102}
3103
3104static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3105{
3106 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3107 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003108 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003109
3110 scid = __le16_to_cpu(rsp->scid);
3111 dcid = __le16_to_cpu(rsp->dcid);
3112
3113 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3114
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003115 mutex_lock(&conn->chan_lock);
3116
3117 chan = __l2cap_get_chan_by_scid(conn, scid);
3118 if (!chan) {
3119 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003120 return 0;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003122
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003123 l2cap_chan_lock(chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003124
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003125 l2cap_chan_del(chan, 0);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02003126
3127 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003129 chan->ops->close(chan->data);
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02003130
3131 mutex_unlock(&conn->chan_lock);
3132
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 return 0;
3134}
3135
3136static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3137{
3138 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003139 u16 type;
3140
3141 type = __le16_to_cpu(req->type);
3142
3143 BT_DBG("type 0x%4.4x", type);
3144
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003145 if (type == L2CAP_IT_FEAT_MASK) {
3146 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003147 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003148 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3149 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3150 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003151 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003152 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3153 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003154 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003155 feat_mask |= L2CAP_FEAT_EXT_FLOW
3156 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003157
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003158 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003159 l2cap_send_cmd(conn, cmd->ident,
3160 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003161 } else if (type == L2CAP_IT_FIXED_CHAN) {
3162 u8 buf[12];
3163 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003164
3165 if (enable_hs)
3166 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3167 else
3168 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3169
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003170 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3171 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003172 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003173 l2cap_send_cmd(conn, cmd->ident,
3174 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003175 } else {
3176 struct l2cap_info_rsp rsp;
3177 rsp.type = cpu_to_le16(type);
3178 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3179 l2cap_send_cmd(conn, cmd->ident,
3180 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3181 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
3183 return 0;
3184}
3185
3186static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3187{
3188 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3189 u16 type, result;
3190
3191 type = __le16_to_cpu(rsp->type);
3192 result = __le16_to_cpu(rsp->result);
3193
3194 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3195
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003196 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3197 if (cmd->ident != conn->info_ident ||
3198 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3199 return 0;
3200
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02003201 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003202
Ville Tervoadb08ed2010-08-04 09:43:33 +03003203 if (result != L2CAP_IR_SUCCESS) {
3204 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3205 conn->info_ident = 0;
3206
3207 l2cap_conn_start(conn);
3208
3209 return 0;
3210 }
3211
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003212 switch (type) {
3213 case L2CAP_IT_FEAT_MASK:
Harvey Harrison83985312008-05-02 16:25:46 -07003214 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003215
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003216 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003217 struct l2cap_info_req req;
3218 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3219
3220 conn->info_ident = l2cap_get_ident(conn);
3221
3222 l2cap_send_cmd(conn, conn->info_ident,
3223 L2CAP_INFO_REQ, sizeof(req), &req);
3224 } else {
3225 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3226 conn->info_ident = 0;
3227
3228 l2cap_conn_start(conn);
3229 }
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003230 break;
3231
3232 case L2CAP_IT_FIXED_CHAN:
3233 conn->fixed_chan_mask = rsp->data[0];
Marcel Holtmann984947d2009-02-06 23:35:19 +01003234 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003235 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003236
3237 l2cap_conn_start(conn);
Andrei Emeltchenko978c93b2012-02-29 10:41:41 +02003238 break;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003239 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003240
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 return 0;
3242}
3243
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003244static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3245 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3246 void *data)
3247{
3248 struct l2cap_create_chan_req *req = data;
3249 struct l2cap_create_chan_rsp rsp;
3250 u16 psm, scid;
3251
3252 if (cmd_len != sizeof(*req))
3253 return -EPROTO;
3254
3255 if (!enable_hs)
3256 return -EINVAL;
3257
3258 psm = le16_to_cpu(req->psm);
3259 scid = le16_to_cpu(req->scid);
3260
3261 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3262
3263 /* Placeholder: Always reject */
3264 rsp.dcid = 0;
3265 rsp.scid = cpu_to_le16(scid);
Andrei Emeltchenko8ce0c492012-03-12 12:13:09 +02003266 rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
3267 rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003268
3269 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3270 sizeof(rsp), &rsp);
3271
3272 return 0;
3273}
3274
3275static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3276 struct l2cap_cmd_hdr *cmd, void *data)
3277{
3278 BT_DBG("conn %p", conn);
3279
3280 return l2cap_connect_rsp(conn, cmd, data);
3281}
3282
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003283static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3284 u16 icid, u16 result)
3285{
3286 struct l2cap_move_chan_rsp rsp;
3287
3288 BT_DBG("icid %d, result %d", icid, result);
3289
3290 rsp.icid = cpu_to_le16(icid);
3291 rsp.result = cpu_to_le16(result);
3292
3293 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3294}
3295
3296static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3297 struct l2cap_chan *chan, u16 icid, u16 result)
3298{
3299 struct l2cap_move_chan_cfm cfm;
3300 u8 ident;
3301
3302 BT_DBG("icid %d, result %d", icid, result);
3303
3304 ident = l2cap_get_ident(conn);
3305 if (chan)
3306 chan->ident = ident;
3307
3308 cfm.icid = cpu_to_le16(icid);
3309 cfm.result = cpu_to_le16(result);
3310
3311 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3312}
3313
3314static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3315 u16 icid)
3316{
3317 struct l2cap_move_chan_cfm_rsp rsp;
3318
3319 BT_DBG("icid %d", icid);
3320
3321 rsp.icid = cpu_to_le16(icid);
3322 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3323}
3324
3325static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3326 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3327{
3328 struct l2cap_move_chan_req *req = data;
3329 u16 icid = 0;
3330 u16 result = L2CAP_MR_NOT_ALLOWED;
3331
3332 if (cmd_len != sizeof(*req))
3333 return -EPROTO;
3334
3335 icid = le16_to_cpu(req->icid);
3336
3337 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3338
3339 if (!enable_hs)
3340 return -EINVAL;
3341
3342 /* Placeholder: Always refuse */
3343 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3344
3345 return 0;
3346}
3347
3348static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3349 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3350{
3351 struct l2cap_move_chan_rsp *rsp = data;
3352 u16 icid, result;
3353
3354 if (cmd_len != sizeof(*rsp))
3355 return -EPROTO;
3356
3357 icid = le16_to_cpu(rsp->icid);
3358 result = le16_to_cpu(rsp->result);
3359
3360 BT_DBG("icid %d, result %d", icid, result);
3361
3362 /* Placeholder: Always unconfirmed */
3363 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3364
3365 return 0;
3366}
3367
3368static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3369 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3370{
3371 struct l2cap_move_chan_cfm *cfm = data;
3372 u16 icid, result;
3373
3374 if (cmd_len != sizeof(*cfm))
3375 return -EPROTO;
3376
3377 icid = le16_to_cpu(cfm->icid);
3378 result = le16_to_cpu(cfm->result);
3379
3380 BT_DBG("icid %d, result %d", icid, result);
3381
3382 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3383
3384 return 0;
3385}
3386
3387static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3388 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3389{
3390 struct l2cap_move_chan_cfm_rsp *rsp = data;
3391 u16 icid;
3392
3393 if (cmd_len != sizeof(*rsp))
3394 return -EPROTO;
3395
3396 icid = le16_to_cpu(rsp->icid);
3397
3398 BT_DBG("icid %d", icid);
3399
3400 return 0;
3401}
3402
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003403static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003404 u16 to_multiplier)
3405{
3406 u16 max_latency;
3407
3408 if (min > max || min < 6 || max > 3200)
3409 return -EINVAL;
3410
3411 if (to_multiplier < 10 || to_multiplier > 3200)
3412 return -EINVAL;
3413
3414 if (max >= to_multiplier * 8)
3415 return -EINVAL;
3416
3417 max_latency = (to_multiplier * 8 / max) - 1;
3418 if (latency > 499 || latency > max_latency)
3419 return -EINVAL;
3420
3421 return 0;
3422}
3423
3424static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3425 struct l2cap_cmd_hdr *cmd, u8 *data)
3426{
3427 struct hci_conn *hcon = conn->hcon;
3428 struct l2cap_conn_param_update_req *req;
3429 struct l2cap_conn_param_update_rsp rsp;
3430 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003431 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003432
3433 if (!(hcon->link_mode & HCI_LM_MASTER))
3434 return -EINVAL;
3435
3436 cmd_len = __le16_to_cpu(cmd->len);
3437 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3438 return -EPROTO;
3439
3440 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003441 min = __le16_to_cpu(req->min);
3442 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003443 latency = __le16_to_cpu(req->latency);
3444 to_multiplier = __le16_to_cpu(req->to_multiplier);
3445
3446 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3447 min, max, latency, to_multiplier);
3448
3449 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003450
3451 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3452 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003453 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3454 else
3455 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3456
3457 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3458 sizeof(rsp), &rsp);
3459
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003460 if (!err)
3461 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3462
Claudio Takahaside731152011-02-11 19:28:55 -02003463 return 0;
3464}
3465
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003466static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3467 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3468{
3469 int err = 0;
3470
3471 switch (cmd->code) {
3472 case L2CAP_COMMAND_REJ:
3473 l2cap_command_rej(conn, cmd, data);
3474 break;
3475
3476 case L2CAP_CONN_REQ:
3477 err = l2cap_connect_req(conn, cmd, data);
3478 break;
3479
3480 case L2CAP_CONN_RSP:
3481 err = l2cap_connect_rsp(conn, cmd, data);
3482 break;
3483
3484 case L2CAP_CONF_REQ:
3485 err = l2cap_config_req(conn, cmd, cmd_len, data);
3486 break;
3487
3488 case L2CAP_CONF_RSP:
3489 err = l2cap_config_rsp(conn, cmd, data);
3490 break;
3491
3492 case L2CAP_DISCONN_REQ:
3493 err = l2cap_disconnect_req(conn, cmd, data);
3494 break;
3495
3496 case L2CAP_DISCONN_RSP:
3497 err = l2cap_disconnect_rsp(conn, cmd, data);
3498 break;
3499
3500 case L2CAP_ECHO_REQ:
3501 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3502 break;
3503
3504 case L2CAP_ECHO_RSP:
3505 break;
3506
3507 case L2CAP_INFO_REQ:
3508 err = l2cap_information_req(conn, cmd, data);
3509 break;
3510
3511 case L2CAP_INFO_RSP:
3512 err = l2cap_information_rsp(conn, cmd, data);
3513 break;
3514
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003515 case L2CAP_CREATE_CHAN_REQ:
3516 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3517 break;
3518
3519 case L2CAP_CREATE_CHAN_RSP:
3520 err = l2cap_create_channel_rsp(conn, cmd, data);
3521 break;
3522
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003523 case L2CAP_MOVE_CHAN_REQ:
3524 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3525 break;
3526
3527 case L2CAP_MOVE_CHAN_RSP:
3528 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3529 break;
3530
3531 case L2CAP_MOVE_CHAN_CFM:
3532 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3533 break;
3534
3535 case L2CAP_MOVE_CHAN_CFM_RSP:
3536 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3537 break;
3538
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003539 default:
3540 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3541 err = -EINVAL;
3542 break;
3543 }
3544
3545 return err;
3546}
3547
3548static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3549 struct l2cap_cmd_hdr *cmd, u8 *data)
3550{
3551 switch (cmd->code) {
3552 case L2CAP_COMMAND_REJ:
3553 return 0;
3554
3555 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003556 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003557
3558 case L2CAP_CONN_PARAM_UPDATE_RSP:
3559 return 0;
3560
3561 default:
3562 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3563 return -EINVAL;
3564 }
3565}
3566
3567static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3568 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569{
3570 u8 *data = skb->data;
3571 int len = skb->len;
3572 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003573 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
3575 l2cap_raw_recv(conn, skb);
3576
3577 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003578 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3580 data += L2CAP_CMD_HDR_SIZE;
3581 len -= L2CAP_CMD_HDR_SIZE;
3582
Al Viro88219a02007-07-29 00:17:25 -07003583 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584
Al Viro88219a02007-07-29 00:17:25 -07003585 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 -07003586
Al Viro88219a02007-07-29 00:17:25 -07003587 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 BT_DBG("corrupted command");
3589 break;
3590 }
3591
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003592 if (conn->hcon->type == LE_LINK)
3593 err = l2cap_le_sig_cmd(conn, &cmd, data);
3594 else
3595 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596
3597 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003598 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003599
3600 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601
3602 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003603 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3605 }
3606
Al Viro88219a02007-07-29 00:17:25 -07003607 data += cmd_len;
3608 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 }
3610
3611 kfree_skb(skb);
3612}
3613
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003614static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003615{
3616 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003617 int hdr_size;
3618
3619 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3620 hdr_size = L2CAP_EXT_HDR_SIZE;
3621 else
3622 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003623
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003624 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003625 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003626 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3627 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3628
3629 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003630 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003631 }
3632 return 0;
3633}
3634
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003635static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003636{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003637 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003638
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003639 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003640
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003641 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003642
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003643 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003644 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003645 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003646 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003647 }
3648
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003649 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003650 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003651
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003652 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003653
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003654 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003655 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003656 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003657 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003658 }
3659}
3660
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003661static 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 -03003662{
3663 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003664 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003665
3666 bt_cb(skb)->tx_seq = tx_seq;
3667 bt_cb(skb)->sar = sar;
3668
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003669 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003670
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003671 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003672
Szymon Janc039d9572011-11-16 09:32:19 +01003673 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003674 if (bt_cb(next_skb)->tx_seq == tx_seq)
3675 return -EINVAL;
3676
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003677 next_tx_seq_offset = __seq_offset(chan,
3678 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003679
3680 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003681 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003682 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003683 }
3684
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003685 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003686 next_skb = NULL;
3687 else
3688 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3689 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003690
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003691 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003692
3693 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003694}
3695
Mat Martineau84084a32011-07-22 14:54:00 -07003696static void append_skb_frag(struct sk_buff *skb,
3697 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003698{
Mat Martineau84084a32011-07-22 14:54:00 -07003699 /* skb->len reflects data in skb as well as all fragments
3700 * skb->data_len reflects only data in fragments
3701 */
3702 if (!skb_has_frag_list(skb))
3703 skb_shinfo(skb)->frag_list = new_frag;
3704
3705 new_frag->next = NULL;
3706
3707 (*last_frag)->next = new_frag;
3708 *last_frag = new_frag;
3709
3710 skb->len += new_frag->len;
3711 skb->data_len += new_frag->len;
3712 skb->truesize += new_frag->truesize;
3713}
3714
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003715static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003716{
3717 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003718
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003719 switch (__get_ctrl_sar(chan, control)) {
3720 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003721 if (chan->sdu)
3722 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003723
Mat Martineau84084a32011-07-22 14:54:00 -07003724 err = chan->ops->recv(chan->data, skb);
3725 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003726
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003727 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003728 if (chan->sdu)
3729 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003730
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003731 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003732 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003733
Mat Martineau84084a32011-07-22 14:54:00 -07003734 if (chan->sdu_len > chan->imtu) {
3735 err = -EMSGSIZE;
3736 break;
3737 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003738
Mat Martineau84084a32011-07-22 14:54:00 -07003739 if (skb->len >= chan->sdu_len)
3740 break;
3741
3742 chan->sdu = skb;
3743 chan->sdu_last_frag = skb;
3744
3745 skb = NULL;
3746 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003747 break;
3748
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003749 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003750 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003751 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003752
Mat Martineau84084a32011-07-22 14:54:00 -07003753 append_skb_frag(chan->sdu, skb,
3754 &chan->sdu_last_frag);
3755 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003756
Mat Martineau84084a32011-07-22 14:54:00 -07003757 if (chan->sdu->len >= chan->sdu_len)
3758 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003759
Mat Martineau84084a32011-07-22 14:54:00 -07003760 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003761 break;
3762
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003763 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003764 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003765 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003766
Mat Martineau84084a32011-07-22 14:54:00 -07003767 append_skb_frag(chan->sdu, skb,
3768 &chan->sdu_last_frag);
3769 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003770
Mat Martineau84084a32011-07-22 14:54:00 -07003771 if (chan->sdu->len != chan->sdu_len)
3772 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003773
Mat Martineau84084a32011-07-22 14:54:00 -07003774 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003775
Mat Martineau84084a32011-07-22 14:54:00 -07003776 if (!err) {
3777 /* Reassembly complete */
3778 chan->sdu = NULL;
3779 chan->sdu_last_frag = NULL;
3780 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003781 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003782 break;
3783 }
3784
Mat Martineau84084a32011-07-22 14:54:00 -07003785 if (err) {
3786 kfree_skb(skb);
3787 kfree_skb(chan->sdu);
3788 chan->sdu = NULL;
3789 chan->sdu_last_frag = NULL;
3790 chan->sdu_len = 0;
3791 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003792
Mat Martineau84084a32011-07-22 14:54:00 -07003793 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003794}
3795
Mat Martineau26f880d2011-07-07 09:39:01 -07003796static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003797{
Mat Martineau26f880d2011-07-07 09:39:01 -07003798 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003799
Mat Martineau26f880d2011-07-07 09:39:01 -07003800 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3801
Szymon Janc77f918b2012-01-11 10:59:48 +01003802 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003803}
3804
3805static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3806{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003807 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003808
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003809 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003810 goto done;
3811
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003812 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003813 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003814 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003815 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003816 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003817
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003818 __clear_retrans_timer(chan);
3819 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003820
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003821 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003822
3823done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003824 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3825 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003826
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003827 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003828}
3829
Mat Martineaue3281402011-07-07 09:39:02 -07003830void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003831{
Mat Martineaue3281402011-07-07 09:39:02 -07003832 if (chan->mode == L2CAP_MODE_ERTM) {
3833 if (busy)
3834 l2cap_ertm_enter_local_busy(chan);
3835 else
3836 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003837 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003838}
3839
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003840static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003841{
3842 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003843 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003844
Mat Martineaue3281402011-07-07 09:39:02 -07003845 while ((skb = skb_peek(&chan->srej_q)) &&
3846 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3847 int err;
3848
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003849 if (bt_cb(skb)->tx_seq != tx_seq)
3850 break;
3851
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003852 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003853 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003854 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003855
3856 if (err < 0) {
3857 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3858 break;
3859 }
3860
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003861 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3862 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003863 }
3864}
3865
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003866static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003867{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003868 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003869 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003870
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003871 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003872 if (l->tx_seq == tx_seq) {
3873 list_del(&l->list);
3874 kfree(l);
3875 return;
3876 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003877 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003878 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003879 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003880 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003881 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003882 }
3883}
3884
Szymon Jancaef89f22011-11-16 09:32:18 +01003885static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003886{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003887 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003888 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003889
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003890 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003891 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003892 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003893 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003894
3895 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003896 if (!new)
3897 return -ENOMEM;
3898
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003899 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003900
3901 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3902
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003903 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003904 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003905
3906 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003907
3908 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003909}
3910
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003911static 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 -03003912{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003913 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003914 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003915 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003916 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003917 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003918 int err = 0;
3919
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003920 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 -03003921 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003922
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003923 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003924 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003925 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003926 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003927 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003928 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003929 }
3930
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003931 chan->expected_ack_seq = req_seq;
3932 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003933
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003934 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003935
3936 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003937 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003938 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003939 goto drop;
3940 }
3941
Szymon Janc77f918b2012-01-11 10:59:48 +01003942 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3943 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3944 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003945 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003946 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003947
Mat Martineau02f1b642011-06-29 14:35:19 -07003948 if (tx_seq == chan->expected_tx_seq)
3949 goto expected;
3950
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003951 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003952 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003953
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003954 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003955 struct srej_list, list);
3956 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003957 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003958 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003959
3960 list_del(&first->list);
3961 kfree(first);
3962
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003963 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003964 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003965 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003966 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003967 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003968 }
3969 } else {
3970 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003971
3972 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003973 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003974 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003975
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003976 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003977 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003978 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003979 return 0;
3980 }
3981 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003982
3983 err = l2cap_send_srejframe(chan, tx_seq);
3984 if (err < 0) {
3985 l2cap_send_disconn_req(chan->conn, chan, -err);
3986 return err;
3987 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003988 }
3989 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003990 expected_tx_seq_offset = __seq_offset(chan,
3991 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003992
3993 /* duplicated tx_seq */
3994 if (tx_seq_offset < expected_tx_seq_offset)
3995 goto drop;
3996
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003997 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003998
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003999 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004000
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03004001 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004002 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004003
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004004 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004005 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004006
Szymon Janc0ef3ef02012-01-11 10:59:46 +01004007 /* Set P-bit only if there are some I-frames to ack. */
4008 if (__clear_ack_timer(chan))
4009 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03004010
Szymon Jancaef89f22011-11-16 09:32:18 +01004011 err = l2cap_send_srejframe(chan, tx_seq);
4012 if (err < 0) {
4013 l2cap_send_disconn_req(chan->conn, chan, -err);
4014 return err;
4015 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004016 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004017 return 0;
4018
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004019expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004020 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004021
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004022 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03004023 bt_cb(skb)->tx_seq = tx_seq;
4024 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03004025 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004026 return 0;
4027 }
4028
Mat Martineau84084a32011-07-22 14:54:00 -07004029 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004030 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
4031
Mat Martineaue3281402011-07-07 09:39:02 -07004032 if (err < 0) {
4033 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
4034 return err;
4035 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03004036
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004037 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004038 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004039 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03004040 }
4041
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03004042
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004043 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
4044 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004045 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03004046 else
4047 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03004048
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004049 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03004050
4051drop:
4052 kfree_skb(skb);
4053 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004054}
4055
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004056static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004057{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004058 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004059 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004060
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004061 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004062 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004063
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004064 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004065 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4066 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4067 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004068 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004069 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004070
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004071 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004072 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004073 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004074 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004075 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004076
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004077 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004078 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004079
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004080 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004081 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004082
4083 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004084 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004085 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004086 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004087
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004088 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4089 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004090 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004091 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004092 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004093 }
4094}
4095
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004096static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004097{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004098 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004099
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004100 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004101
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004102 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004103
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004104 chan->expected_ack_seq = tx_seq;
4105 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004106
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004107 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004108 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004109 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004110 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004111 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004112
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004113 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4114 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004115 }
4116}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004117static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004118{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004119 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004120
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004121 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004122
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004123 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004124
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004125 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004126 chan->expected_ack_seq = tx_seq;
4127 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004128
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004129 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004130 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004131
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004132 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004133
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004134 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004135 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004136 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004137 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004138 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004139 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004140 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004141 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004142 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004143 l2cap_retransmit_one_frame(chan, tx_seq);
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. Padovane2ab4352011-06-10 21:28:49 -03004146 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004147 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004148 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004149 }
4150 }
4151}
4152
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004153static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004154{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004155 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004156
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004157 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004158
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004159 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004160 chan->expected_ack_seq = tx_seq;
4161 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004162
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004163 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004164 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004165
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004166 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004167 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004168 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004169 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004170 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004171 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004172
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004173 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004174 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004175 } else {
4176 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4177 l2cap_send_sframe(chan, rx_control);
4178 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004179}
4180
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004181static 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 -03004182{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004183 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004184
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004185 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004186 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004187 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004188 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004189 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004190 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004191 }
4192
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004193 switch (__get_ctrl_super(chan, rx_control)) {
4194 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004195 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004196 break;
4197
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004198 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004199 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004200 break;
4201
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004202 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004203 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004204 break;
4205
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004206 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004207 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004208 break;
4209 }
4210
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004211 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004212 return 0;
4213}
4214
Szymon Janccad8f1d02012-01-23 10:06:05 +01004215static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004216{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004217 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004218 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004219 int len, next_tx_seq_offset, req_seq_offset;
4220
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004221 control = __get_control(chan, skb->data);
4222 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004223 len = skb->len;
4224
4225 /*
4226 * We can just drop the corrupted I-frame here.
4227 * Receiver will miss it and start proper recovery
4228 * procedures and ask retransmission.
4229 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004230 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004231 goto drop;
4232
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004233 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004234 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004235
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004236 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004237 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004238
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004239 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004240 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004241 goto drop;
4242 }
4243
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004244 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004245
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004246 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4247
4248 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4249 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004250
4251 /* check for invalid req-seq */
4252 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004253 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004254 goto drop;
4255 }
4256
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004257 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004258 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004259 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004260 goto drop;
4261 }
4262
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004263 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004264 } else {
4265 if (len != 0) {
4266 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004267 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004268 goto drop;
4269 }
4270
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004271 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004272 }
4273
4274 return 0;
4275
4276drop:
4277 kfree_skb(skb);
4278 return 0;
4279}
4280
Linus Torvalds1da177e2005-04-16 15:20:36 -07004281static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4282{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004283 struct l2cap_chan *chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004284 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004285 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004286 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004288 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004289 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 BT_DBG("unknown cid 0x%4.4x", cid);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004291 /* Drop packet and return */
Dan Carpenter33790132012-02-28 09:52:46 +03004292 kfree_skb(skb);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004293 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 }
4295
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004296 l2cap_chan_lock(chan);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004297
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004298 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004300 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 goto drop;
4302
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004303 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004304 case L2CAP_MODE_BASIC:
4305 /* If socket recv buffers overflows we drop data here
4306 * which is *bad* because L2CAP has to be reliable.
4307 * But we don't have any other choice. L2CAP doesn't
4308 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004310 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004311 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004313 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004314 goto done;
4315 break;
4316
4317 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004318 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004319
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004320 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004321
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004322 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004323 control = __get_control(chan, skb->data);
4324 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004325 len = skb->len;
4326
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004327 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004328 goto drop;
4329
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004330 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004331 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004332
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004333 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004334 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004335
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004336 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004337 goto drop;
4338
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004339 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004340
Mat Martineau84084a32011-07-22 14:54:00 -07004341 if (chan->expected_tx_seq != tx_seq) {
4342 /* Frame(s) missing - must discard partial SDU */
4343 kfree_skb(chan->sdu);
4344 chan->sdu = NULL;
4345 chan->sdu_last_frag = NULL;
4346 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004347
Mat Martineau84084a32011-07-22 14:54:00 -07004348 /* TODO: Notify userland of missing data */
4349 }
4350
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004351 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004352
4353 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4354 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004355
4356 goto done;
4357
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004358 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004359 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004360 break;
4361 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362
4363drop:
4364 kfree_skb(skb);
4365
4366done:
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004367 l2cap_chan_unlock(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +02004368
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 return 0;
4370}
4371
Al Viro8e036fc2007-07-29 00:16:36 -07004372static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004374 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004376 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4377 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378 goto drop;
4379
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004380 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004382 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383 goto drop;
4384
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004385 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 goto drop;
4387
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004388 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004389 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390
4391drop:
4392 kfree_skb(skb);
4393
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 return 0;
4395}
4396
Andrei Emeltchenkod9b88702012-03-12 12:13:08 +02004397static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
4398 struct sk_buff *skb)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004399{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004400 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004401
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004402 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4403 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004404 goto drop;
4405
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004406 BT_DBG("chan %p, len %d", chan, skb->len);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004407
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004408 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004409 goto drop;
4410
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004411 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004412 goto drop;
4413
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004414 if (!chan->ops->recv(chan->data, skb))
Andrei Emeltchenko5b4ceda2012-02-24 16:35:32 +02004415 return 0;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004416
4417drop:
4418 kfree_skb(skb);
4419
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004420 return 0;
4421}
4422
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4424{
4425 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004426 u16 cid, len;
4427 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428
4429 skb_pull(skb, L2CAP_HDR_SIZE);
4430 cid = __le16_to_cpu(lh->cid);
4431 len = __le16_to_cpu(lh->len);
4432
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004433 if (len != skb->len) {
4434 kfree_skb(skb);
4435 return;
4436 }
4437
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4439
4440 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004441 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004442 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 l2cap_sig_channel(conn, skb);
4444 break;
4445
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004446 case L2CAP_CID_CONN_LESS:
Andrei Emeltchenko097db762012-03-09 14:16:17 +02004447 psm = get_unaligned((__le16 *) skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 skb_pull(skb, 2);
4449 l2cap_conless_channel(conn, psm, skb);
4450 break;
4451
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004452 case L2CAP_CID_LE_DATA:
4453 l2cap_att_channel(conn, cid, skb);
4454 break;
4455
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004456 case L2CAP_CID_SMP:
4457 if (smp_sig_channel(conn, skb))
4458 l2cap_conn_del(conn->hcon, EACCES);
4459 break;
4460
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461 default:
4462 l2cap_data_channel(conn, cid, skb);
4463 break;
4464 }
4465}
4466
4467/* ---- L2CAP interface with lower layer (HCI) ---- */
4468
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004469int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470{
4471 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004472 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4475
4476 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004477 read_lock(&chan_list_lock);
4478 list_for_each_entry(c, &chan_list, global_l) {
4479 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004480
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004481 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 continue;
4483
4484 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004485 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004486 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004487 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004489 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4490 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004491 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004492 lm2 |= HCI_LM_MASTER;
4493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004495 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496
4497 return exact ? lm1 : lm2;
4498}
4499
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004500int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501{
Marcel Holtmann01394182006-07-03 10:02:46 +02004502 struct l2cap_conn *conn;
4503
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4505
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507 conn = l2cap_conn_add(hcon, status);
4508 if (conn)
4509 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004510 } else
Joe Perchese1750722011-06-29 18:18:29 -07004511 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512
4513 return 0;
4514}
4515
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004516int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004517{
4518 struct l2cap_conn *conn = hcon->l2cap_data;
4519
4520 BT_DBG("hcon %p", hcon);
4521
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004522 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004523 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004524 return conn->disc_reason;
4525}
4526
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004527int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528{
4529 BT_DBG("hcon %p reason %d", hcon, reason);
4530
Joe Perchese1750722011-06-29 18:18:29 -07004531 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 return 0;
4533}
4534
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004535static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004536{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004537 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004538 return;
4539
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004540 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004541 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004542 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004543 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004544 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004545 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004546 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004547 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004548 }
4549}
4550
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004551int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004553 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004554 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555
Marcel Holtmann01394182006-07-03 10:02:46 +02004556 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004558
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 BT_DBG("conn %p", conn);
4560
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004561 if (hcon->type == LE_LINK) {
4562 smp_distribute_keys(conn, 0);
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02004563 cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004564 }
4565
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004566 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004568 list_for_each_entry(chan, &conn->chan_l, list) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004569 l2cap_chan_lock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004571 BT_DBG("chan->scid %d", chan->scid);
4572
4573 if (chan->scid == L2CAP_CID_LE_DATA) {
4574 if (!status && encrypt) {
4575 chan->sec_level = hcon->sec_level;
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02004576 l2cap_chan_ready(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004577 }
4578
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004579 l2cap_chan_unlock(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004580 continue;
4581 }
4582
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004583 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004584 l2cap_chan_unlock(chan);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004585 continue;
4586 }
4587
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004588 if (!status && (chan->state == BT_CONNECTED ||
4589 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004590 l2cap_check_encryption(chan, encrypt);
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004591 l2cap_chan_unlock(chan);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004592 continue;
4593 }
4594
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004595 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004596 if (!status) {
Andrei Emeltchenko9b27f352012-02-24 16:00:00 +02004597 l2cap_send_conn_req(chan);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004598 } else {
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004599 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004600 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004601 } else if (chan->state == BT_CONNECT2) {
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004602 struct sock *sk = chan->sk;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004603 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004604 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004605
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004606 lock_sock(sk);
4607
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004608 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004609 if (bt_sk(sk)->defer_setup) {
4610 struct sock *parent = bt_sk(sk)->parent;
4611 res = L2CAP_CR_PEND;
4612 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004613 if (parent)
4614 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004615 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004616 __l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004617 res = L2CAP_CR_SUCCESS;
4618 stat = L2CAP_CS_NO_INFO;
4619 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004620 } else {
Andrei Emeltchenko0e587be2012-02-21 12:54:57 +02004621 __l2cap_state_change(chan, BT_DISCONN);
Marcel Holtmannba13ccd2012-03-01 14:25:33 -08004622 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004623 res = L2CAP_CR_SEC_BLOCK;
4624 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004625 }
4626
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004627 release_sock(sk);
4628
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004629 rsp.scid = cpu_to_le16(chan->dcid);
4630 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004631 rsp.result = cpu_to_le16(res);
4632 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004633 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4634 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 }
4636
Andrei Emeltchenko6be36552012-02-22 17:11:56 +02004637 l2cap_chan_unlock(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 }
4639
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004640 mutex_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004641
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 return 0;
4643}
4644
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004645int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646{
4647 struct l2cap_conn *conn = hcon->l2cap_data;
4648
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004649 if (!conn)
4650 conn = l2cap_conn_add(hcon, 0);
4651
4652 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 goto drop;
4654
4655 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4656
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004657 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004659 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004660 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661 int len;
4662
4663 if (conn->rx_len) {
4664 BT_ERR("Unexpected start frame (len %d)", skb->len);
4665 kfree_skb(conn->rx_skb);
4666 conn->rx_skb = NULL;
4667 conn->rx_len = 0;
4668 l2cap_conn_unreliable(conn, ECOMM);
4669 }
4670
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004671 /* Start fragment always begin with Basic L2CAP header */
4672 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 BT_ERR("Frame is too short (len %d)", skb->len);
4674 l2cap_conn_unreliable(conn, ECOMM);
4675 goto drop;
4676 }
4677
4678 hdr = (struct l2cap_hdr *) skb->data;
4679 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004680 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681
4682 if (len == skb->len) {
4683 /* Complete frame received */
4684 l2cap_recv_frame(conn, skb);
4685 return 0;
4686 }
4687
4688 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4689
4690 if (skb->len > len) {
4691 BT_ERR("Frame is too long (len %d, expected len %d)",
4692 skb->len, len);
4693 l2cap_conn_unreliable(conn, ECOMM);
4694 goto drop;
4695 }
4696
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004697 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004698
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004699 if (chan && chan->sk) {
4700 struct sock *sk = chan->sk;
Andrei Emeltchenko3df91ea2012-02-21 12:54:55 +02004701 lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004702
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004703 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004704 BT_ERR("Frame exceeding recv MTU (len %d, "
4705 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004706 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004707 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004708 l2cap_conn_unreliable(conn, ECOMM);
4709 goto drop;
4710 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004711 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004712 }
4713
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004715 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4716 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 goto drop;
4718
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004719 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004720 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 conn->rx_len = len - skb->len;
4722 } else {
4723 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4724
4725 if (!conn->rx_len) {
4726 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4727 l2cap_conn_unreliable(conn, ECOMM);
4728 goto drop;
4729 }
4730
4731 if (skb->len > conn->rx_len) {
4732 BT_ERR("Fragment is too long (len %d, expected %d)",
4733 skb->len, conn->rx_len);
4734 kfree_skb(conn->rx_skb);
4735 conn->rx_skb = NULL;
4736 conn->rx_len = 0;
4737 l2cap_conn_unreliable(conn, ECOMM);
4738 goto drop;
4739 }
4740
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004741 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004742 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 conn->rx_len -= skb->len;
4744
4745 if (!conn->rx_len) {
4746 /* Complete frame received */
4747 l2cap_recv_frame(conn, conn->rx_skb);
4748 conn->rx_skb = NULL;
4749 }
4750 }
4751
4752drop:
4753 kfree_skb(skb);
4754 return 0;
4755}
4756
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004757static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004759 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004761 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004763 list_for_each_entry(c, &chan_list, global_l) {
4764 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004766 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 +01004767 batostr(&bt_sk(sk)->src),
4768 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004769 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004770 c->scid, c->dcid, c->imtu, c->omtu,
4771 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004774 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004775
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004776 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777}
4778
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004779static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4780{
4781 return single_open(file, l2cap_debugfs_show, inode->i_private);
4782}
4783
4784static const struct file_operations l2cap_debugfs_fops = {
4785 .open = l2cap_debugfs_open,
4786 .read = seq_read,
4787 .llseek = seq_lseek,
4788 .release = single_release,
4789};
4790
4791static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004793int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794{
4795 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004796
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004797 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 if (err < 0)
4799 return err;
4800
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004801 if (bt_debugfs) {
4802 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4803 bt_debugfs, NULL, &l2cap_debugfs_fops);
4804 if (!l2cap_debugfs)
4805 BT_ERR("Failed to create L2CAP debug file");
4806 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809}
4810
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004811void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004813 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004814 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815}
4816
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004817module_param(disable_ertm, bool, 0644);
4818MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");