blob: 26dc3f6a8346714f36cf1bd59349193c11f1415d [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.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
7 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation;
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090017 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090022 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 SOFTWARE IS DISCLAIMED.
25*/
26
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020027/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30
31#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/sched.h>
36#include <linux/slab.h>
37#include <linux/poll.h>
38#include <linux/fcntl.h>
39#include <linux/init.h>
40#include <linux/interrupt.h>
41#include <linux/socket.h>
42#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080044#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010045#include <linux/debugfs.h>
46#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030047#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030048#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/sock.h>
50
51#include <asm/system.h>
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
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030075static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
76
Marcel Holtmann01394182006-07-03 10:02:46 +020077/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030078
79static inline void chan_hold(struct l2cap_chan *c)
80{
81 atomic_inc(&c->refcnt);
82}
83
84static inline void chan_put(struct l2cap_chan *c)
85{
86 if (atomic_dec_and_test(&c->refcnt))
87 kfree(c);
88}
89
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030090static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020091{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030092 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030093
94 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030095 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030096 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020097 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030098 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020099}
100
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
105 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300106 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300107 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200108 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300109 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200110}
111
112/* Find channel with given SCID.
113 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300114static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200115{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300116 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300117
118 read_lock(&conn->chan_lock);
119 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300120 if (c)
121 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300122 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300123 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200124}
125
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300126static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200127{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300128 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300129
130 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300131 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300132 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200133 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300134 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200135}
136
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300137static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200138{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300139 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300140
141 read_lock(&conn->chan_lock);
142 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300143 if (c)
144 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300145 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300146 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200147}
148
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300149static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300150{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300151 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300152
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300153 list_for_each_entry(c, &chan_list, global_l) {
154 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100155 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300156 }
Szymon Janc250938c2011-11-16 09:32:22 +0100157 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300158}
159
160int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
161{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300162 int err;
163
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300164 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300165
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300166 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300167 err = -EADDRINUSE;
168 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300169 }
170
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300171 if (psm) {
172 chan->psm = psm;
173 chan->sport = psm;
174 err = 0;
175 } else {
176 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300177
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300178 err = -EINVAL;
179 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300180 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300181 chan->psm = cpu_to_le16(p);
182 chan->sport = cpu_to_le16(p);
183 err = 0;
184 break;
185 }
186 }
187
188done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300189 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300190 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300191}
192
193int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
194{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300195 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300196
197 chan->scid = scid;
198
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300199 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300200
201 return 0;
202}
203
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300204static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200205{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300206 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200207
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300208 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300209 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200210 return cid;
211 }
212
213 return 0;
214}
215
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300216static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300217{
Andrei Emeltchenko457f4852011-10-31 16:17:21 +0200218 BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300219
Mat Martineau942ecc92011-06-29 14:35:21 -0700220 if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
Mat Martineau774e5652011-06-29 14:35:20 -0700221 chan_hold(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300222}
223
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300224static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300225{
Mat Martineau774e5652011-06-29 14:35:20 -0700226 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300227
Mat Martineau774e5652011-06-29 14:35:20 -0700228 if (timer_pending(timer) && del_timer(timer))
229 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300230}
231
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200232static char *state_to_string(int state)
233{
234 switch(state) {
235 case BT_CONNECTED:
236 return "BT_CONNECTED";
237 case BT_OPEN:
238 return "BT_OPEN";
239 case BT_BOUND:
240 return "BT_BOUND";
241 case BT_LISTEN:
242 return "BT_LISTEN";
243 case BT_CONNECT:
244 return "BT_CONNECT";
245 case BT_CONNECT2:
246 return "BT_CONNECT2";
247 case BT_CONFIG:
248 return "BT_CONFIG";
249 case BT_DISCONN:
250 return "BT_DISCONN";
251 case BT_CLOSED:
252 return "BT_CLOSED";
253 }
254
255 return "invalid state";
256}
257
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300258static void l2cap_state_change(struct l2cap_chan *chan, int state)
259{
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200260 BT_DBG("%p %s -> %s", chan, state_to_string(chan->state),
261 state_to_string(state));
262
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300263 chan->state = state;
264 chan->ops->state_change(chan->data, state);
265}
266
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300267static void l2cap_chan_timeout(unsigned long arg)
268{
269 struct l2cap_chan *chan = (struct l2cap_chan *) arg;
270 struct sock *sk = chan->sk;
271 int reason;
272
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300273 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300274
275 bh_lock_sock(sk);
276
277 if (sock_owned_by_user(sk)) {
278 /* sk is owned by user. Try again later */
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -0200279 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300280 bh_unlock_sock(sk);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300281 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300282 return;
283 }
284
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300285 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300286 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300287 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300288 chan->sec_level != BT_SECURITY_SDP)
289 reason = ECONNREFUSED;
290 else
291 reason = ETIMEDOUT;
292
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300293 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300294
295 bh_unlock_sock(sk);
296
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300297 chan->ops->close(chan->data);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300298 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300299}
300
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300301struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200302{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300303 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200304
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300305 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
306 if (!chan)
307 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200308
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300309 chan->sk = sk;
310
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300311 write_lock_bh(&chan_list_lock);
312 list_add(&chan->global_l, &chan_list);
313 write_unlock_bh(&chan_list_lock);
314
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300315 setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
316
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300317 chan->state = BT_OPEN;
318
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300319 atomic_set(&chan->refcnt, 1);
320
Szymon Jancabc545b2011-11-03 16:05:44 +0100321 BT_DBG("sk %p chan %p", sk, chan);
322
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300323 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200324}
325
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300326void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300327{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300328 write_lock_bh(&chan_list_lock);
329 list_del(&chan->global_l);
330 write_unlock_bh(&chan_list_lock);
331
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300332 chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300333}
334
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300335static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200336{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300337 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300338 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200339
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200340 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100341
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300342 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200343
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300344 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300345 if (conn->hcon->type == LE_LINK) {
346 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300347 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300348 chan->scid = L2CAP_CID_LE_DATA;
349 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300350 } else {
351 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300352 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300353 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300354 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300355 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200356 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300357 chan->scid = L2CAP_CID_CONN_LESS;
358 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300359 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200360 } else {
361 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300362 chan->scid = L2CAP_CID_SIGNALING;
363 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300364 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200365 }
366
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300367 chan->local_id = L2CAP_BESTEFFORT_ID;
368 chan->local_stype = L2CAP_SERV_BESTEFFORT;
369 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
370 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
371 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
372 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
373
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300374 chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300375
376 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200377}
378
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900379/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200380 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300381static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200382{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300383 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300384 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200385 struct sock *parent = bt_sk(sk)->parent;
386
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300387 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200388
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300389 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200390
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900391 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300392 /* Delete from channel list */
393 write_lock_bh(&conn->chan_lock);
394 list_del(&chan->list);
395 write_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300396 chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300397
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300398 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200399 hci_conn_put(conn->hcon);
400 }
401
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300402 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200403 sock_set_flag(sk, SOCK_ZAPPED);
404
405 if (err)
406 sk->sk_err = err;
407
408 if (parent) {
409 bt_accept_unlink(sk);
410 parent->sk_data_ready(parent, 0);
411 } else
412 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300413
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300414 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
415 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300416 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300417
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300418 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300419
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300420 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300421 struct srej_list *l, *tmp;
422
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300423 __clear_retrans_timer(chan);
424 __clear_monitor_timer(chan);
425 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300426
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300427 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300428
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300429 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300430 list_del(&l->list);
431 kfree(l);
432 }
433 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200434}
435
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300436static void l2cap_chan_cleanup_listen(struct sock *parent)
437{
438 struct sock *sk;
439
440 BT_DBG("parent %p", parent);
441
442 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300443 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300444 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300445 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300446 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300447 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300448 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300449 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300450 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300451}
452
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300453void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300454{
455 struct l2cap_conn *conn = chan->conn;
456 struct sock *sk = chan->sk;
457
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300458 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300459
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300460 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300461 case BT_LISTEN:
462 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300463
464 l2cap_state_change(chan, BT_CLOSED);
465 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300466 break;
467
468 case BT_CONNECTED:
469 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300470 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300471 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300472 __clear_chan_timer(chan);
473 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300474 l2cap_send_disconn_req(conn, chan, reason);
475 } else
476 l2cap_chan_del(chan, reason);
477 break;
478
479 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300480 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300481 conn->hcon->type == ACL_LINK) {
482 struct l2cap_conn_rsp rsp;
483 __u16 result;
484
485 if (bt_sk(sk)->defer_setup)
486 result = L2CAP_CR_SEC_BLOCK;
487 else
488 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300489 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300490
491 rsp.scid = cpu_to_le16(chan->dcid);
492 rsp.dcid = cpu_to_le16(chan->scid);
493 rsp.result = cpu_to_le16(result);
494 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
495 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
496 sizeof(rsp), &rsp);
497 }
498
499 l2cap_chan_del(chan, reason);
500 break;
501
502 case BT_CONNECT:
503 case BT_DISCONN:
504 l2cap_chan_del(chan, reason);
505 break;
506
507 default:
508 sock_set_flag(sk, SOCK_ZAPPED);
509 break;
510 }
511}
512
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300513static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530514{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300515 if (chan->chan_type == L2CAP_CHAN_RAW) {
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_DEDICATED_BONDING_MITM;
519 case BT_SECURITY_MEDIUM:
520 return HCI_AT_DEDICATED_BONDING;
521 default:
522 return HCI_AT_NO_BONDING;
523 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300524 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300525 if (chan->sec_level == BT_SECURITY_LOW)
526 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530527
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300528 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530529 return HCI_AT_NO_BONDING_MITM;
530 else
531 return HCI_AT_NO_BONDING;
532 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300533 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530534 case BT_SECURITY_HIGH:
535 return HCI_AT_GENERAL_BONDING_MITM;
536 case BT_SECURITY_MEDIUM:
537 return HCI_AT_GENERAL_BONDING;
538 default:
539 return HCI_AT_NO_BONDING;
540 }
541 }
542}
543
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200544/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200545int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200546{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300547 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100548 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200549
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300550 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100551
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300552 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200553}
554
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200555static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200556{
557 u8 id;
558
559 /* Get next available identificator.
560 * 1 - 128 are used by kernel.
561 * 129 - 199 are reserved.
562 * 200 - 254 are used by utilities like l2ping, etc.
563 */
564
565 spin_lock_bh(&conn->lock);
566
567 if (++conn->tx_ident > 128)
568 conn->tx_ident = 1;
569
570 id = conn->tx_ident;
571
572 spin_unlock_bh(&conn->lock);
573
574 return id;
575}
576
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300577static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200578{
579 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200580 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200581
582 BT_DBG("code 0x%2.2x", code);
583
584 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300585 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200586
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200587 if (lmp_no_flush_capable(conn->hcon->hdev))
588 flags = ACL_START_NO_FLUSH;
589 else
590 flags = ACL_START;
591
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700592 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200593 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700594
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200595 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200596}
597
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200598static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
599{
600 struct hci_conn *hcon = chan->conn->hcon;
601 u16 flags;
602
603 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
604 skb->priority);
605
606 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
607 lmp_no_flush_capable(hcon->hdev))
608 flags = ACL_START_NO_FLUSH;
609 else
610 flags = ACL_START;
611
612 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
613 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614}
615
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300616static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300617{
618 struct sk_buff *skb;
619 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300620 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300621 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300622
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300623 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300624 return;
625
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300626 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
627 hlen = L2CAP_EXT_HDR_SIZE;
628 else
629 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300630
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300631 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300632 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300633
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300634 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300635
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300636 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300637
638 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300639
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300640 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300641 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300642
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300643 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300644 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300645
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300646 skb = bt_skb_alloc(count, GFP_ATOMIC);
647 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300648 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300649
650 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300651 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300652 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300653
654 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300655
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300656 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300657 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
658 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300659 }
660
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200661 skb->priority = HCI_PRIO_MAX;
662 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300663}
664
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300665static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300666{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300667 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300668 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300669 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300670 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300671 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300672
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300673 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300674
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300675 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300676}
677
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300678static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300679{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300680 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300681}
682
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300683static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200684{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300685 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200686
687 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100688 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
689 return;
690
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200691 if (l2cap_chan_check_security(chan) &&
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300692 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200693 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300694 req.scid = cpu_to_le16(chan->scid);
695 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200696
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300697 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300698 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200699
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300700 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
701 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200702 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200703 } else {
704 struct l2cap_info_req req;
705 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
706
707 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
708 conn->info_ident = l2cap_get_ident(conn);
709
710 mod_timer(&conn->info_timer, jiffies +
711 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
712
713 l2cap_send_cmd(conn, conn->info_ident,
714 L2CAP_INFO_REQ, sizeof(req), &req);
715 }
716}
717
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300718static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
719{
720 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300721 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300722 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
723
724 switch (mode) {
725 case L2CAP_MODE_ERTM:
726 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
727 case L2CAP_MODE_STREAMING:
728 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
729 default:
730 return 0x00;
731 }
732}
733
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300734static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300735{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300736 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300737 struct l2cap_disconn_req req;
738
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300739 if (!conn)
740 return;
741
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300742 sk = chan->sk;
743
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300744 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300745 __clear_retrans_timer(chan);
746 __clear_monitor_timer(chan);
747 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300748 }
749
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300750 req.dcid = cpu_to_le16(chan->dcid);
751 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300752 l2cap_send_cmd(conn, l2cap_get_ident(conn),
753 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300754
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300755 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300756 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300757}
758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200760static void l2cap_conn_start(struct l2cap_conn *conn)
761{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300762 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200763
764 BT_DBG("conn %p", conn);
765
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300766 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200767
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300768 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300769 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300770
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200771 bh_lock_sock(sk);
772
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300773 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200774 bh_unlock_sock(sk);
775 continue;
776 }
777
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300778 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300779 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300780
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200781 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300782 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300783 bh_unlock_sock(sk);
784 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200785 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300786
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300787 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
788 && test_bit(CONF_STATE2_DEVICE,
789 &chan->conf_state)) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300790 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300791 * so release the lock */
Gustavo F. Padovan2461daa2011-06-17 12:57:25 -0300792 read_unlock(&conn->chan_lock);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300793 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan2461daa2011-06-17 12:57:25 -0300794 read_lock(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300795 bh_unlock_sock(sk);
796 continue;
797 }
798
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300799 req.scid = cpu_to_le16(chan->scid);
800 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300801
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300802 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300803 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300804
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300805 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
806 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300807
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300808 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200809 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300810 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300811 rsp.scid = cpu_to_le16(chan->dcid);
812 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200813
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200814 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100815 if (bt_sk(sk)->defer_setup) {
816 struct sock *parent = bt_sk(sk)->parent;
817 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
818 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000819 if (parent)
820 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100821
822 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300823 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100824 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
825 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
826 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200827 } else {
828 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
829 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
830 }
831
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300832 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
833 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300834
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300835 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300836 rsp.result != L2CAP_CR_SUCCESS) {
837 bh_unlock_sock(sk);
838 continue;
839 }
840
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300841 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300842 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300843 l2cap_build_conf_req(chan, buf), buf);
844 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200845 }
846
847 bh_unlock_sock(sk);
848 }
849
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300850 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200851}
852
Ville Tervob62f3282011-02-10 22:38:50 -0300853/* Find socket with cid and source bdaddr.
854 * Returns closest match, locked.
855 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300856static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300857{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300858 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300859
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300860 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300861
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300862 list_for_each_entry(c, &chan_list, global_l) {
863 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300864
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300865 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300866 continue;
867
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300868 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300869 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300870 if (!bacmp(&bt_sk(sk)->src, src)) {
871 read_unlock(&chan_list_lock);
872 return c;
873 }
Ville Tervob62f3282011-02-10 22:38:50 -0300874
875 /* Closest match */
876 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300877 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300878 }
879 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300880
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300881 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300882
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300883 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300884}
885
886static void l2cap_le_conn_ready(struct l2cap_conn *conn)
887{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300888 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300889 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300890
891 BT_DBG("");
892
893 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300894 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300895 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300896 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300897 return;
898
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300899 parent = pchan->sk;
900
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300901 bh_lock_sock(parent);
902
Ville Tervob62f3282011-02-10 22:38:50 -0300903 /* Check for backlog size */
904 if (sk_acceptq_is_full(parent)) {
905 BT_DBG("backlog full %d", parent->sk_ack_backlog);
906 goto clean;
907 }
908
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300909 chan = pchan->ops->new_connection(pchan->data);
910 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300911 goto clean;
912
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300913 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300914
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300915 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300916
917 hci_conn_hold(conn->hcon);
918
Ville Tervob62f3282011-02-10 22:38:50 -0300919 bacpy(&bt_sk(sk)->src, conn->src);
920 bacpy(&bt_sk(sk)->dst, conn->dst);
921
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300922 bt_accept_enqueue(parent, sk);
923
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300924 __l2cap_chan_add(conn, chan);
925
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300926 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300927
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300928 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300929 parent->sk_data_ready(parent, 0);
930
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300931 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300932
933clean:
934 bh_unlock_sock(parent);
935}
936
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300937static void l2cap_chan_ready(struct sock *sk)
938{
939 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
940 struct sock *parent = bt_sk(sk)->parent;
941
942 BT_DBG("sk %p, parent %p", sk, parent);
943
944 chan->conf_state = 0;
945 __clear_chan_timer(chan);
946
Vinicius Costa Gomes43f3dc42011-06-20 18:53:18 -0300947 l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300948 sk->sk_state_change(sk);
949
950 if (parent)
951 parent->sk_data_ready(parent, 0);
952}
953
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200954static void l2cap_conn_ready(struct l2cap_conn *conn)
955{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300956 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200957
958 BT_DBG("conn %p", conn);
959
Ville Tervob62f3282011-02-10 22:38:50 -0300960 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
961 l2cap_le_conn_ready(conn);
962
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300963 if (conn->hcon->out && conn->hcon->type == LE_LINK)
964 smp_conn_security(conn, conn->hcon->pending_sec_level);
965
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300966 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200967
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300968 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300969 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300970
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200971 bh_lock_sock(sk);
972
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300973 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300974 if (smp_conn_security(conn, chan->sec_level))
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300975 l2cap_chan_ready(sk);
Ville Tervoacd7d372011-02-10 22:38:49 -0300976
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300977 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300978 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300979 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200980 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300981
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300982 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300983 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200984
985 bh_unlock_sock(sk);
986 }
987
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300988 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200989}
990
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200991/* Notify sockets that we cannot guaranty reliability anymore */
992static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
993{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300994 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200995
996 BT_DBG("conn %p", conn);
997
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300998 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200999
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001000 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001001 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001002
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +03001003 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001004 sk->sk_err = err;
1005 }
1006
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001007 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001008}
1009
1010static void l2cap_info_timeout(unsigned long arg)
1011{
1012 struct l2cap_conn *conn = (void *) arg;
1013
Marcel Holtmann984947d2009-02-06 23:35:19 +01001014 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01001015 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01001016
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001017 l2cap_conn_start(conn);
1018}
1019
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001020static void l2cap_conn_del(struct hci_conn *hcon, int err)
1021{
1022 struct l2cap_conn *conn = hcon->l2cap_data;
1023 struct l2cap_chan *chan, *l;
1024 struct sock *sk;
1025
1026 if (!conn)
1027 return;
1028
1029 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1030
1031 kfree_skb(conn->rx_skb);
1032
1033 /* Kill channels */
1034 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
1035 sk = chan->sk;
1036 bh_lock_sock(sk);
1037 l2cap_chan_del(chan, err);
1038 bh_unlock_sock(sk);
1039 chan->ops->close(chan->data);
1040 }
1041
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001042 hci_chan_del(conn->hchan);
1043
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001044 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
1045 del_timer_sync(&conn->info_timer);
1046
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001047 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001048 del_timer(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001049 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001050 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001051
1052 hcon->l2cap_data = NULL;
1053 kfree(conn);
1054}
1055
1056static void security_timeout(unsigned long arg)
1057{
1058 struct l2cap_conn *conn = (void *) arg;
1059
1060 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1061}
1062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1064{
Marcel Holtmann01394182006-07-03 10:02:46 +02001065 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001066 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067
Marcel Holtmann01394182006-07-03 10:02:46 +02001068 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 return conn;
1070
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001071 hchan = hci_chan_create(hcon);
1072 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001075 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1076 if (!conn) {
1077 hci_chan_del(hchan);
1078 return NULL;
1079 }
1080
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 hcon->l2cap_data = conn;
1082 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001083 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001085 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001086
Ville Tervoacd7d372011-02-10 22:38:49 -03001087 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1088 conn->mtu = hcon->hdev->le_mtu;
1089 else
1090 conn->mtu = hcon->hdev->acl_mtu;
1091
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 conn->src = &hcon->hdev->bdaddr;
1093 conn->dst = &hcon->dst;
1094
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001095 conn->feat_mask = 0;
1096
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001098 rwlock_init(&conn->chan_lock);
1099
1100 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001102 if (hcon->type == LE_LINK)
1103 setup_timer(&conn->security_timer, security_timeout,
1104 (unsigned long) conn);
1105 else
Ville Tervob62f3282011-02-10 22:38:50 -03001106 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +00001107 (unsigned long) conn);
1108
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001109 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001110
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 return conn;
1112}
1113
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001114static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001116 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001117 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001118 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119}
1120
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
1123/* Find socket with psm and source bdaddr.
1124 * Returns closest match.
1125 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001126static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001128 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001130 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001131
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001132 list_for_each_entry(c, &chan_list, global_l) {
1133 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001134
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001135 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 continue;
1137
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001138 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001140 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001141 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001142 return c;
1143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
1145 /* Closest match */
1146 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001147 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 }
1149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001151 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001152
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001153 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154}
1155
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001156int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001158 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 bdaddr_t *src = &bt_sk(sk)->src;
1160 bdaddr_t *dst = &bt_sk(sk)->dst;
1161 struct l2cap_conn *conn;
1162 struct hci_conn *hcon;
1163 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001164 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001165 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001167 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001168 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001170 hdev = hci_get_route(dst, src);
1171 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 return -EHOSTUNREACH;
1173
1174 hci_dev_lock_bh(hdev);
1175
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001176 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001177
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001178 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001179 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001180 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001181 else
1182 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001183 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001184
Ville Tervo30e76272011-02-22 16:10:53 -03001185 if (IS_ERR(hcon)) {
1186 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
1190 conn = l2cap_conn_add(hcon, 0);
1191 if (!conn) {
1192 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001193 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 goto done;
1195 }
1196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 /* Update source addr of the socket */
1198 bacpy(src, conn->src);
1199
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001200 l2cap_chan_add(conn, chan);
1201
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001202 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001203 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
1205 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001206 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001207 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001208 if (l2cap_chan_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001209 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001210 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001211 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 }
1213
Ville Tervo30e76272011-02-22 16:10:53 -03001214 err = 0;
1215
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216done:
1217 hci_dev_unlock_bh(hdev);
1218 hci_dev_put(hdev);
1219 return err;
1220}
1221
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001222int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001223{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001224 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001225 DECLARE_WAITQUEUE(wait, current);
1226 int err = 0;
1227 int timeo = HZ/5;
1228
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001229 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001230 set_current_state(TASK_INTERRUPTIBLE);
1231 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001232 if (!timeo)
1233 timeo = HZ/5;
1234
1235 if (signal_pending(current)) {
1236 err = sock_intr_errno(timeo);
1237 break;
1238 }
1239
1240 release_sock(sk);
1241 timeo = schedule_timeout(timeo);
1242 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001243 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001244
1245 err = sock_error(sk);
1246 if (err)
1247 break;
1248 }
1249 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001250 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001251 return err;
1252}
1253
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001254static void l2cap_monitor_timeout(unsigned long arg)
1255{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001256 struct l2cap_chan *chan = (void *) arg;
1257 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001258
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001259 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001260
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001261 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001262 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001263 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001264 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001265 return;
1266 }
1267
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001268 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001269 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001270
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001271 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001272 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001273}
1274
1275static void l2cap_retrans_timeout(unsigned long arg)
1276{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001277 struct l2cap_chan *chan = (void *) arg;
1278 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001279
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001280 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001281
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001282 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001283 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001284 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001285
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001286 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001287
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001288 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001289 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001290}
1291
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001292static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001293{
1294 struct sk_buff *skb;
1295
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001296 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001297 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001298 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001299 break;
1300
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001301 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001302 kfree_skb(skb);
1303
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001304 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001305 }
1306
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001307 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001308 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001309}
1310
Szymon Janc67c9e842011-07-28 16:24:33 +02001311static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001312{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001313 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001314 u32 control;
1315 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001316
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001317 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001318 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001319 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001320 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001321
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001322 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001323 fcs = crc16(0, (u8 *)skb->data,
1324 skb->len - L2CAP_FCS_SIZE);
1325 put_unaligned_le16(fcs,
1326 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001327 }
1328
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001329 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001330
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001331 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001332 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001333}
1334
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001335static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001336{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001337 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001338 u16 fcs;
1339 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001340
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001341 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001342 if (!skb)
1343 return;
1344
Szymon Jancd1726b62011-11-16 09:32:20 +01001345 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001346 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001347 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001348
Szymon Jancd1726b62011-11-16 09:32:20 +01001349 skb = skb_queue_next(&chan->tx_q, skb);
1350 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001351
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001352 if (chan->remote_max_tx &&
1353 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001354 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001355 return;
1356 }
1357
1358 tx_skb = skb_clone(skb, GFP_ATOMIC);
1359 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001360
1361 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001362 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001363
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001364 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001365 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001366
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001367 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001368 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001369
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001370 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001371
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001372 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001373 fcs = crc16(0, (u8 *)tx_skb->data,
1374 tx_skb->len - L2CAP_FCS_SIZE);
1375 put_unaligned_le16(fcs,
1376 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001377 }
1378
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001379 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001380}
1381
Szymon Janc67c9e842011-07-28 16:24:33 +02001382static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001383{
1384 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001385 u16 fcs;
1386 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001387 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001388
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001389 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001390 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001391
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001392 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001393
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001394 if (chan->remote_max_tx &&
1395 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001396 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001397 break;
1398 }
1399
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001400 tx_skb = skb_clone(skb, GFP_ATOMIC);
1401
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001402 bt_cb(skb)->retries++;
1403
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001404 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001405 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001406
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001407 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001408 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001409
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001410 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001411 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001412
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001413 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001414
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001415 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001416 fcs = crc16(0, (u8 *)skb->data,
1417 tx_skb->len - L2CAP_FCS_SIZE);
1418 put_unaligned_le16(fcs, skb->data +
1419 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001420 }
1421
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001422 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001423
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001424 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001425
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001426 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001427
1428 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001429
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301430 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001431 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301432
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001433 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001434
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001435 if (skb_queue_is_last(&chan->tx_q, skb))
1436 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001437 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001438 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001439
1440 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001441 }
1442
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001443 return nsent;
1444}
1445
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001446static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001447{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001448 int ret;
1449
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001450 if (!skb_queue_empty(&chan->tx_q))
1451 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001452
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001453 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001454 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001455 return ret;
1456}
1457
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001458static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001459{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001460 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001461
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001462 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001463
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001464 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001465 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001466 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001467 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001468 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001469 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001470
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001471 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001472 return;
1473
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001474 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001475 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001476}
1477
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001478static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001479{
1480 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001481 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001482
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001483 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001484 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001485
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001486 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001487 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001488
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001489 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001490}
1491
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001492static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001494 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001495 struct sk_buff **frag;
1496 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001498 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001499 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500
1501 sent += count;
1502 len -= count;
1503
1504 /* Continuation fragments (no L2CAP header) */
1505 frag = &skb_shinfo(skb)->frag_list;
1506 while (len) {
1507 count = min_t(unsigned int, conn->mtu, len);
1508
1509 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1510 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001511 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001512 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1513 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001515 (*frag)->priority = skb->priority;
1516
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 sent += count;
1518 len -= count;
1519
1520 frag = &(*frag)->next;
1521 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522
1523 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001524}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001526static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1527 struct msghdr *msg, size_t len,
1528 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001529{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001530 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001531 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001532 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001533 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001534 struct l2cap_hdr *lh;
1535
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001536 BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001537
1538 count = min_t(unsigned int, (conn->mtu - hlen), len);
1539 skb = bt_skb_send_alloc(sk, count + hlen,
1540 msg->msg_flags & MSG_DONTWAIT, &err);
1541 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001542 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001543
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001544 skb->priority = priority;
1545
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001546 /* Create L2CAP header */
1547 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001548 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001549 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001550 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001551
1552 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1553 if (unlikely(err < 0)) {
1554 kfree_skb(skb);
1555 return ERR_PTR(err);
1556 }
1557 return skb;
1558}
1559
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001560static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1561 struct msghdr *msg, size_t len,
1562 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001563{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001564 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001565 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001566 struct sk_buff *skb;
1567 int err, count, hlen = L2CAP_HDR_SIZE;
1568 struct l2cap_hdr *lh;
1569
1570 BT_DBG("sk %p len %d", sk, (int)len);
1571
1572 count = min_t(unsigned int, (conn->mtu - hlen), len);
1573 skb = bt_skb_send_alloc(sk, count + hlen,
1574 msg->msg_flags & MSG_DONTWAIT, &err);
1575 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001576 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001577
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001578 skb->priority = priority;
1579
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001580 /* Create L2CAP header */
1581 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001582 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001583 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1584
1585 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1586 if (unlikely(err < 0)) {
1587 kfree_skb(skb);
1588 return ERR_PTR(err);
1589 }
1590 return skb;
1591}
1592
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001593static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1594 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001595 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001596{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001597 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001598 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001599 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001600 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001601 struct l2cap_hdr *lh;
1602
1603 BT_DBG("sk %p len %d", sk, (int)len);
1604
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001605 if (!conn)
1606 return ERR_PTR(-ENOTCONN);
1607
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001608 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1609 hlen = L2CAP_EXT_HDR_SIZE;
1610 else
1611 hlen = L2CAP_ENH_HDR_SIZE;
1612
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001613 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001614 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001615
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001616 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001617 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001618
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001619 count = min_t(unsigned int, (conn->mtu - hlen), len);
1620 skb = bt_skb_send_alloc(sk, count + hlen,
1621 msg->msg_flags & MSG_DONTWAIT, &err);
1622 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001623 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001624
1625 /* Create L2CAP header */
1626 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001627 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001628 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001629
1630 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1631
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001632 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001633 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001634
1635 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1636 if (unlikely(err < 0)) {
1637 kfree_skb(skb);
1638 return ERR_PTR(err);
1639 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001640
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001641 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001642 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001643
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001644 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001645 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646}
1647
Szymon Janc67c9e842011-07-28 16:24:33 +02001648static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001649{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001650 struct sk_buff *skb;
1651 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001652 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001653 size_t size = 0;
1654
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001655 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001656 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001657 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001658 if (IS_ERR(skb))
1659 return PTR_ERR(skb);
1660
1661 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001662 len -= chan->remote_mps;
1663 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001664
1665 while (len > 0) {
1666 size_t buflen;
1667
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001668 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001669 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001670 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001671 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001672 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001673 buflen = len;
1674 }
1675
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001676 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001677 if (IS_ERR(skb)) {
1678 skb_queue_purge(&sar_queue);
1679 return PTR_ERR(skb);
1680 }
1681
1682 __skb_queue_tail(&sar_queue, skb);
1683 len -= buflen;
1684 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001685 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001686 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1687 if (chan->tx_send_head == NULL)
1688 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001689
1690 return size;
1691}
1692
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001693int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1694 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001695{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001696 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001697 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001698 int err;
1699
1700 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001701 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001702 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001703 if (IS_ERR(skb))
1704 return PTR_ERR(skb);
1705
1706 l2cap_do_send(chan, skb);
1707 return len;
1708 }
1709
1710 switch (chan->mode) {
1711 case L2CAP_MODE_BASIC:
1712 /* Check outgoing MTU */
1713 if (len > chan->omtu)
1714 return -EMSGSIZE;
1715
1716 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001717 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001718 if (IS_ERR(skb))
1719 return PTR_ERR(skb);
1720
1721 l2cap_do_send(chan, skb);
1722 err = len;
1723 break;
1724
1725 case L2CAP_MODE_ERTM:
1726 case L2CAP_MODE_STREAMING:
1727 /* Entire SDU fits into one PDU */
1728 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001729 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001730 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1731 0);
1732 if (IS_ERR(skb))
1733 return PTR_ERR(skb);
1734
1735 __skb_queue_tail(&chan->tx_q, skb);
1736
1737 if (chan->tx_send_head == NULL)
1738 chan->tx_send_head = skb;
1739
1740 } else {
1741 /* Segment SDU into multiples PDUs */
1742 err = l2cap_sar_segment_sdu(chan, msg, len);
1743 if (err < 0)
1744 return err;
1745 }
1746
1747 if (chan->mode == L2CAP_MODE_STREAMING) {
1748 l2cap_streaming_send(chan);
1749 err = len;
1750 break;
1751 }
1752
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001753 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1754 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001755 err = len;
1756 break;
1757 }
1758
1759 err = l2cap_ertm_send(chan);
1760 if (err >= 0)
1761 err = len;
1762
1763 break;
1764
1765 default:
1766 BT_DBG("bad state %1.1x", chan->mode);
1767 err = -EBADFD;
1768 }
1769
1770 return err;
1771}
1772
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773/* Copy frame to all raw sockets on that connection */
1774static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1775{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001777 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778
1779 BT_DBG("conn %p", conn);
1780
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001781 read_lock(&conn->chan_lock);
1782 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001783 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001784 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 continue;
1786
1787 /* Don't send frame to the socket it came from */
1788 if (skb->sk == sk)
1789 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001790 nskb = skb_clone(skb, GFP_ATOMIC);
1791 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 continue;
1793
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001794 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 kfree_skb(nskb);
1796 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001797 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798}
1799
1800/* ---- L2CAP signalling commands ---- */
1801static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1802 u8 code, u8 ident, u16 dlen, void *data)
1803{
1804 struct sk_buff *skb, **frag;
1805 struct l2cap_cmd_hdr *cmd;
1806 struct l2cap_hdr *lh;
1807 int len, count;
1808
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001809 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1810 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811
1812 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1813 count = min_t(unsigned int, conn->mtu, len);
1814
1815 skb = bt_skb_alloc(count, GFP_ATOMIC);
1816 if (!skb)
1817 return NULL;
1818
1819 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001820 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001821
1822 if (conn->hcon->type == LE_LINK)
1823 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1824 else
1825 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826
1827 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1828 cmd->code = code;
1829 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001830 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831
1832 if (dlen) {
1833 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1834 memcpy(skb_put(skb, count), data, count);
1835 data += count;
1836 }
1837
1838 len -= skb->len;
1839
1840 /* Continuation fragments (no L2CAP header) */
1841 frag = &skb_shinfo(skb)->frag_list;
1842 while (len) {
1843 count = min_t(unsigned int, conn->mtu, len);
1844
1845 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1846 if (!*frag)
1847 goto fail;
1848
1849 memcpy(skb_put(*frag, count), data, count);
1850
1851 len -= count;
1852 data += count;
1853
1854 frag = &(*frag)->next;
1855 }
1856
1857 return skb;
1858
1859fail:
1860 kfree_skb(skb);
1861 return NULL;
1862}
1863
1864static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1865{
1866 struct l2cap_conf_opt *opt = *ptr;
1867 int len;
1868
1869 len = L2CAP_CONF_OPT_SIZE + opt->len;
1870 *ptr += len;
1871
1872 *type = opt->type;
1873 *olen = opt->len;
1874
1875 switch (opt->len) {
1876 case 1:
1877 *val = *((u8 *) opt->val);
1878 break;
1879
1880 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001881 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 break;
1883
1884 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001885 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 break;
1887
1888 default:
1889 *val = (unsigned long) opt->val;
1890 break;
1891 }
1892
1893 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1894 return len;
1895}
1896
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1898{
1899 struct l2cap_conf_opt *opt = *ptr;
1900
1901 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1902
1903 opt->type = type;
1904 opt->len = len;
1905
1906 switch (len) {
1907 case 1:
1908 *((u8 *) opt->val) = val;
1909 break;
1910
1911 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001912 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 break;
1914
1915 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001916 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 break;
1918
1919 default:
1920 memcpy(opt->val, (void *) val, len);
1921 break;
1922 }
1923
1924 *ptr += L2CAP_CONF_OPT_SIZE + len;
1925}
1926
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001927static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1928{
1929 struct l2cap_conf_efs efs;
1930
Szymon Janc1ec918c2011-11-16 09:32:21 +01001931 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001932 case L2CAP_MODE_ERTM:
1933 efs.id = chan->local_id;
1934 efs.stype = chan->local_stype;
1935 efs.msdu = cpu_to_le16(chan->local_msdu);
1936 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1937 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1938 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1939 break;
1940
1941 case L2CAP_MODE_STREAMING:
1942 efs.id = 1;
1943 efs.stype = L2CAP_SERV_BESTEFFORT;
1944 efs.msdu = cpu_to_le16(chan->local_msdu);
1945 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1946 efs.acc_lat = 0;
1947 efs.flush_to = 0;
1948 break;
1949
1950 default:
1951 return;
1952 }
1953
1954 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
1955 (unsigned long) &efs);
1956}
1957
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001958static void l2cap_ack_timeout(unsigned long arg)
1959{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001960 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001961
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001962 bh_lock_sock(chan->sk);
1963 l2cap_send_ack(chan);
1964 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001965}
1966
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001967static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001968{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001969 struct sock *sk = chan->sk;
1970
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001971 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001972 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001973 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001974 chan->num_acked = 0;
1975 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001976
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001977 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1978 (unsigned long) chan);
1979 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1980 (unsigned long) chan);
1981 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001982
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001983 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001984
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001985 INIT_LIST_HEAD(&chan->srej_l);
1986
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001987
1988 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001989}
1990
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001991static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1992{
1993 switch (mode) {
1994 case L2CAP_MODE_STREAMING:
1995 case L2CAP_MODE_ERTM:
1996 if (l2cap_mode_supported(mode, remote_feat_mask))
1997 return mode;
1998 /* fall through */
1999 default:
2000 return L2CAP_MODE_BASIC;
2001 }
2002}
2003
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002004static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2005{
2006 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2007}
2008
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002009static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2010{
2011 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2012}
2013
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002014static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2015{
2016 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002017 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002018 /* use extended control field */
2019 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002020 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2021 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002022 chan->tx_win = min_t(u16, chan->tx_win,
2023 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002024 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2025 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002026}
2027
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002028static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002031 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002033 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002035 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002037 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002038 goto done;
2039
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002040 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002041 case L2CAP_MODE_STREAMING:
2042 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002043 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002044 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002045
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002046 if (__l2cap_efs_supported(chan))
2047 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2048
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002049 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002050 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002051 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002052 break;
2053 }
2054
2055done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002056 if (chan->imtu != L2CAP_DEFAULT_MTU)
2057 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002058
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002059 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002060 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002061 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2062 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002063 break;
2064
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002065 rfc.mode = L2CAP_MODE_BASIC;
2066 rfc.txwin_size = 0;
2067 rfc.max_transmit = 0;
2068 rfc.retrans_timeout = 0;
2069 rfc.monitor_timeout = 0;
2070 rfc.max_pdu_size = 0;
2071
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002072 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2073 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002074 break;
2075
2076 case L2CAP_MODE_ERTM:
2077 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002078 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002079 rfc.retrans_timeout = 0;
2080 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002081
2082 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2083 L2CAP_EXT_HDR_SIZE -
2084 L2CAP_SDULEN_SIZE -
2085 L2CAP_FCS_SIZE);
2086 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002087
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002088 l2cap_txwin_setup(chan);
2089
2090 rfc.txwin_size = min_t(u16, chan->tx_win,
2091 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002092
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002093 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2094 (unsigned long) &rfc);
2095
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002096 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2097 l2cap_add_opt_efs(&ptr, chan);
2098
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002099 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002100 break;
2101
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002102 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002103 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002104 chan->fcs = L2CAP_FCS_NONE;
2105 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002106 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002107
2108 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2109 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2110 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002111 break;
2112
2113 case L2CAP_MODE_STREAMING:
2114 rfc.mode = L2CAP_MODE_STREAMING;
2115 rfc.txwin_size = 0;
2116 rfc.max_transmit = 0;
2117 rfc.retrans_timeout = 0;
2118 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002119
2120 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2121 L2CAP_EXT_HDR_SIZE -
2122 L2CAP_SDULEN_SIZE -
2123 L2CAP_FCS_SIZE);
2124 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002125
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002126 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2127 (unsigned long) &rfc);
2128
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002129 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2130 l2cap_add_opt_efs(&ptr, chan);
2131
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002132 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002133 break;
2134
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002135 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002136 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002137 chan->fcs = L2CAP_FCS_NONE;
2138 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002139 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002140 break;
2141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002143 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002144 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145
2146 return ptr - data;
2147}
2148
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002149static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002151 struct l2cap_conf_rsp *rsp = data;
2152 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002153 void *req = chan->conf_req;
2154 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002155 int type, hint, olen;
2156 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002157 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002158 struct l2cap_conf_efs efs;
2159 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002160 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002161 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002162 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002164 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002165
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002166 while (len >= L2CAP_CONF_OPT_SIZE) {
2167 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002169 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002170 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002171
2172 switch (type) {
2173 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002174 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002175 break;
2176
2177 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002178 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002179 break;
2180
2181 case L2CAP_CONF_QOS:
2182 break;
2183
Marcel Holtmann6464f352007-10-20 13:39:51 +02002184 case L2CAP_CONF_RFC:
2185 if (olen == sizeof(rfc))
2186 memcpy(&rfc, (void *) val, olen);
2187 break;
2188
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002189 case L2CAP_CONF_FCS:
2190 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002191 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002192 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002193
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002194 case L2CAP_CONF_EFS:
2195 remote_efs = 1;
2196 if (olen == sizeof(efs))
2197 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002198 break;
2199
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002200 case L2CAP_CONF_EWS:
2201 if (!enable_hs)
2202 return -ECONNREFUSED;
2203
2204 set_bit(FLAG_EXT_CTRL, &chan->flags);
2205 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002206 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002207 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002208 break;
2209
2210 default:
2211 if (hint)
2212 break;
2213
2214 result = L2CAP_CONF_UNKNOWN;
2215 *((u8 *) ptr++) = type;
2216 break;
2217 }
2218 }
2219
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002220 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002221 goto done;
2222
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002223 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002224 case L2CAP_MODE_STREAMING:
2225 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002226 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002227 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002228 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002229 break;
2230 }
2231
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002232 if (remote_efs) {
2233 if (__l2cap_efs_supported(chan))
2234 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2235 else
2236 return -ECONNREFUSED;
2237 }
2238
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002239 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002240 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002241
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002242 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002243 }
2244
2245done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002246 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002247 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002248 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002249
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002250 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002251 return -ECONNREFUSED;
2252
2253 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2254 sizeof(rfc), (unsigned long) &rfc);
2255 }
2256
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002257 if (result == L2CAP_CONF_SUCCESS) {
2258 /* Configure output options and let the other side know
2259 * which ones we don't like. */
2260
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002261 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2262 result = L2CAP_CONF_UNACCEPT;
2263 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002264 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002265 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002266 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002267 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002268
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002269 if (remote_efs) {
2270 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2271 efs.stype != L2CAP_SERV_NOTRAFIC &&
2272 efs.stype != chan->local_stype) {
2273
2274 result = L2CAP_CONF_UNACCEPT;
2275
2276 if (chan->num_conf_req >= 1)
2277 return -ECONNREFUSED;
2278
2279 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002280 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002281 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002282 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002283 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002284 result = L2CAP_CONF_PENDING;
2285 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002286 }
2287 }
2288
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002289 switch (rfc.mode) {
2290 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002291 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002292 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002293 break;
2294
2295 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002296 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2297 chan->remote_tx_win = rfc.txwin_size;
2298 else
2299 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2300
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002301 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002302
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002303 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2304 chan->conn->mtu -
2305 L2CAP_EXT_HDR_SIZE -
2306 L2CAP_SDULEN_SIZE -
2307 L2CAP_FCS_SIZE);
2308 rfc.max_pdu_size = cpu_to_le16(size);
2309 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002310
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002311 rfc.retrans_timeout =
2312 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2313 rfc.monitor_timeout =
2314 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002315
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002316 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002317
2318 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2319 sizeof(rfc), (unsigned long) &rfc);
2320
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002321 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2322 chan->remote_id = efs.id;
2323 chan->remote_stype = efs.stype;
2324 chan->remote_msdu = le16_to_cpu(efs.msdu);
2325 chan->remote_flush_to =
2326 le32_to_cpu(efs.flush_to);
2327 chan->remote_acc_lat =
2328 le32_to_cpu(efs.acc_lat);
2329 chan->remote_sdu_itime =
2330 le32_to_cpu(efs.sdu_itime);
2331 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2332 sizeof(efs), (unsigned long) &efs);
2333 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002334 break;
2335
2336 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002337 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2338 chan->conn->mtu -
2339 L2CAP_EXT_HDR_SIZE -
2340 L2CAP_SDULEN_SIZE -
2341 L2CAP_FCS_SIZE);
2342 rfc.max_pdu_size = cpu_to_le16(size);
2343 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002344
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002345 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002346
2347 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2348 sizeof(rfc), (unsigned long) &rfc);
2349
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002350 break;
2351
2352 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002353 result = L2CAP_CONF_UNACCEPT;
2354
2355 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002356 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002357 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002358
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002359 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002360 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002361 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002362 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002363 rsp->result = cpu_to_le16(result);
2364 rsp->flags = cpu_to_le16(0x0000);
2365
2366 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367}
2368
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002369static 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 -03002370{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002371 struct l2cap_conf_req *req = data;
2372 void *ptr = req->data;
2373 int type, olen;
2374 unsigned long val;
2375 struct l2cap_conf_rfc rfc;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002376 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002377
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002378 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002379
2380 while (len >= L2CAP_CONF_OPT_SIZE) {
2381 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2382
2383 switch (type) {
2384 case L2CAP_CONF_MTU:
2385 if (val < L2CAP_DEFAULT_MIN_MTU) {
2386 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002387 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002388 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002389 chan->imtu = val;
2390 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002391 break;
2392
2393 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002394 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002395 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002396 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002397 break;
2398
2399 case L2CAP_CONF_RFC:
2400 if (olen == sizeof(rfc))
2401 memcpy(&rfc, (void *)val, olen);
2402
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002403 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002404 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002405 return -ECONNREFUSED;
2406
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002407 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002408
2409 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2410 sizeof(rfc), (unsigned long) &rfc);
2411 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002412
2413 case L2CAP_CONF_EWS:
2414 chan->tx_win = min_t(u16, val,
2415 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002416 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2417 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002418 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002419
2420 case L2CAP_CONF_EFS:
2421 if (olen == sizeof(efs))
2422 memcpy(&efs, (void *)val, olen);
2423
2424 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2425 efs.stype != L2CAP_SERV_NOTRAFIC &&
2426 efs.stype != chan->local_stype)
2427 return -ECONNREFUSED;
2428
2429 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2430 sizeof(efs), (unsigned long) &efs);
2431 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002432 }
2433 }
2434
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002435 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002436 return -ECONNREFUSED;
2437
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002438 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002439
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002440 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002441 switch (rfc.mode) {
2442 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002443 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2444 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2445 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002446
2447 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2448 chan->local_msdu = le16_to_cpu(efs.msdu);
2449 chan->local_sdu_itime =
2450 le32_to_cpu(efs.sdu_itime);
2451 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2452 chan->local_flush_to =
2453 le32_to_cpu(efs.flush_to);
2454 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002455 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002456
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002457 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002458 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002459 }
2460 }
2461
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002462 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002463 req->flags = cpu_to_le16(0x0000);
2464
2465 return ptr - data;
2466}
2467
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002468static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469{
2470 struct l2cap_conf_rsp *rsp = data;
2471 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002473 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002475 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002476 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002477 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478
2479 return ptr - data;
2480}
2481
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002482void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002483{
2484 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002485 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002486 u8 buf[128];
2487
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002488 rsp.scid = cpu_to_le16(chan->dcid);
2489 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002490 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2491 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2492 l2cap_send_cmd(conn, chan->ident,
2493 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2494
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002495 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002496 return;
2497
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002498 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2499 l2cap_build_conf_req(chan, buf), buf);
2500 chan->num_conf_req++;
2501}
2502
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002503static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002504{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002505 int type, olen;
2506 unsigned long val;
2507 struct l2cap_conf_rfc rfc;
2508
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002509 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002510
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002511 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002512 return;
2513
2514 while (len >= L2CAP_CONF_OPT_SIZE) {
2515 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2516
2517 switch (type) {
2518 case L2CAP_CONF_RFC:
2519 if (olen == sizeof(rfc))
2520 memcpy(&rfc, (void *)val, olen);
2521 goto done;
2522 }
2523 }
2524
2525done:
2526 switch (rfc.mode) {
2527 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002528 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2529 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2530 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002531 break;
2532 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002533 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002534 }
2535}
2536
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002537static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2538{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002539 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002540
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002541 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002542 return 0;
2543
2544 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2545 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002546 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002547
2548 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002549 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002550
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002551 l2cap_conn_start(conn);
2552 }
2553
2554 return 0;
2555}
2556
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2558{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2560 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002561 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002562 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002563 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564
2565 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002566 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567
2568 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2569
2570 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002571 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2572 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 result = L2CAP_CR_BAD_PSM;
2574 goto sendresp;
2575 }
2576
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002577 parent = pchan->sk;
2578
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002579 bh_lock_sock(parent);
2580
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002581 /* Check if the ACL is secure enough (if not SDP) */
2582 if (psm != cpu_to_le16(0x0001) &&
2583 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002584 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002585 result = L2CAP_CR_SEC_BLOCK;
2586 goto response;
2587 }
2588
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 result = L2CAP_CR_NO_MEM;
2590
2591 /* Check for backlog size */
2592 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002593 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 goto response;
2595 }
2596
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002597 chan = pchan->ops->new_connection(pchan->data);
2598 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 goto response;
2600
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002601 sk = chan->sk;
2602
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002603 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604
2605 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002606 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2607 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002609 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 goto response;
2611 }
2612
2613 hci_conn_hold(conn->hcon);
2614
Linus Torvalds1da177e2005-04-16 15:20:36 -07002615 bacpy(&bt_sk(sk)->src, conn->src);
2616 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002617 chan->psm = psm;
2618 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002620 bt_accept_enqueue(parent, sk);
2621
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002622 __l2cap_chan_add(conn, chan);
2623
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002624 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002626 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002628 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629
Marcel Holtmann984947d2009-02-06 23:35:19 +01002630 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002631 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002632 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002633 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002634 result = L2CAP_CR_PEND;
2635 status = L2CAP_CS_AUTHOR_PEND;
2636 parent->sk_data_ready(parent, 0);
2637 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002638 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002639 result = L2CAP_CR_SUCCESS;
2640 status = L2CAP_CS_NO_INFO;
2641 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002642 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002643 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002644 result = L2CAP_CR_PEND;
2645 status = L2CAP_CS_AUTHEN_PEND;
2646 }
2647 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002648 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002649 result = L2CAP_CR_PEND;
2650 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 }
2652
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002653 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654
2655response:
2656 bh_unlock_sock(parent);
2657
2658sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002659 rsp.scid = cpu_to_le16(scid);
2660 rsp.dcid = cpu_to_le16(dcid);
2661 rsp.result = cpu_to_le16(result);
2662 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002664
2665 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2666 struct l2cap_info_req info;
2667 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2668
2669 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2670 conn->info_ident = l2cap_get_ident(conn);
2671
2672 mod_timer(&conn->info_timer, jiffies +
2673 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2674
2675 l2cap_send_cmd(conn, conn->info_ident,
2676 L2CAP_INFO_REQ, sizeof(info), &info);
2677 }
2678
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002679 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002680 result == L2CAP_CR_SUCCESS) {
2681 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002682 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002683 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002684 l2cap_build_conf_req(chan, buf), buf);
2685 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002686 }
2687
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 return 0;
2689}
2690
2691static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2692{
2693 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2694 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002695 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002696 struct sock *sk;
2697 u8 req[128];
2698
2699 scid = __le16_to_cpu(rsp->scid);
2700 dcid = __le16_to_cpu(rsp->dcid);
2701 result = __le16_to_cpu(rsp->result);
2702 status = __le16_to_cpu(rsp->status);
2703
2704 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2705
2706 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002707 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002708 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002709 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002711 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002712 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002713 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 }
2715
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002716 sk = chan->sk;
2717
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 switch (result) {
2719 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002720 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002721 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002722 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002723 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002724
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002725 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002726 break;
2727
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002729 l2cap_build_conf_req(chan, req), req);
2730 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 break;
2732
2733 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002734 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 break;
2736
2737 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002738 /* don't delete l2cap channel if sk is owned by user */
2739 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002740 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002741 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002742 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002743 break;
2744 }
2745
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002746 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 break;
2748 }
2749
2750 bh_unlock_sock(sk);
2751 return 0;
2752}
2753
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002754static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002755{
2756 /* FCS is enabled only in ERTM or streaming mode, if one or both
2757 * sides request it.
2758 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002759 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002760 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002761 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002762 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002763}
2764
Al Viro88219a02007-07-29 00:17:25 -07002765static 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 -07002766{
2767 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2768 u16 dcid, flags;
2769 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002770 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002772 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773
2774 dcid = __le16_to_cpu(req->dcid);
2775 flags = __le16_to_cpu(req->flags);
2776
2777 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2778
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002779 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002780 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 return -ENOENT;
2782
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002783 sk = chan->sk;
2784
David S. Miller033b1142011-07-21 13:38:42 -07002785 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002786 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002787
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002788 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2789 rej.scid = cpu_to_le16(chan->scid);
2790 rej.dcid = cpu_to_le16(chan->dcid);
2791
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002792 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2793 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002794 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002795 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002796
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002797 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002798 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002799 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002800 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002801 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002802 L2CAP_CONF_REJECT, flags), rsp);
2803 goto unlock;
2804 }
2805
2806 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002807 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2808 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809
2810 if (flags & 0x0001) {
2811 /* Incomplete config. Send empty response. */
2812 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002813 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002814 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 goto unlock;
2816 }
2817
2818 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002819 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002820 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002821 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002823 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002825 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002826 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002827
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002828 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002829 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002830
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002831 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002832 goto unlock;
2833
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002834 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002835 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002836
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002837 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002838
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002839 chan->next_tx_seq = 0;
2840 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002841 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002842 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002843 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002844
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002846 goto unlock;
2847 }
2848
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002849 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002850 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002852 l2cap_build_conf_req(chan, buf), buf);
2853 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 }
2855
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002856 /* Got Conf Rsp PENDING from remote side and asume we sent
2857 Conf Rsp PENDING in the code above */
2858 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2859 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2860
2861 /* check compatibility */
2862
2863 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2864 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2865
2866 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002867 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002868 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2869 }
2870
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871unlock:
2872 bh_unlock_sock(sk);
2873 return 0;
2874}
2875
2876static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2877{
2878 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2879 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002880 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002882 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883
2884 scid = __le16_to_cpu(rsp->scid);
2885 flags = __le16_to_cpu(rsp->flags);
2886 result = __le16_to_cpu(rsp->result);
2887
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002888 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2889 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002891 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002892 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002893 return 0;
2894
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002895 sk = chan->sk;
2896
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 switch (result) {
2898 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002899 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002900 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002901 break;
2902
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002903 case L2CAP_CONF_PENDING:
2904 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2905
2906 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2907 char buf[64];
2908
2909 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2910 buf, &result);
2911 if (len < 0) {
2912 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2913 goto done;
2914 }
2915
2916 /* check compatibility */
2917
2918 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2919 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2920
2921 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002922 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002923 L2CAP_CONF_SUCCESS, 0x0000), buf);
2924 }
2925 goto done;
2926
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002928 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002929 char req[64];
2930
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002931 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002932 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002933 goto done;
2934 }
2935
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002936 /* throw out any old stored conf requests */
2937 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002938 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2939 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002940 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002941 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002942 goto done;
2943 }
2944
2945 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2946 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002947 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002948 if (result != L2CAP_CONF_SUCCESS)
2949 goto done;
2950 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 }
2952
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002953 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002954 sk->sk_err = ECONNRESET;
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002955 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002956 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002957 goto done;
2958 }
2959
2960 if (flags & 0x01)
2961 goto done;
2962
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002963 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002965 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002966 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002967
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002968 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002969 chan->next_tx_seq = 0;
2970 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002971 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002972 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002973 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002974
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 l2cap_chan_ready(sk);
2976 }
2977
2978done:
2979 bh_unlock_sock(sk);
2980 return 0;
2981}
2982
2983static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2984{
2985 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2986 struct l2cap_disconn_rsp rsp;
2987 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002988 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 struct sock *sk;
2990
2991 scid = __le16_to_cpu(req->scid);
2992 dcid = __le16_to_cpu(req->dcid);
2993
2994 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2995
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002996 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002997 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002998 return 0;
2999
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003000 sk = chan->sk;
3001
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003002 rsp.dcid = cpu_to_le16(chan->scid);
3003 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3005
3006 sk->sk_shutdown = SHUTDOWN_MASK;
3007
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02003008 /* don't delete l2cap channel if sk is owned by user */
3009 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003010 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03003011 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02003012 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02003013 bh_unlock_sock(sk);
3014 return 0;
3015 }
3016
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003017 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 bh_unlock_sock(sk);
3019
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003020 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021 return 0;
3022}
3023
3024static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3025{
3026 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3027 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003028 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 struct sock *sk;
3030
3031 scid = __le16_to_cpu(rsp->scid);
3032 dcid = __le16_to_cpu(rsp->dcid);
3033
3034 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3035
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003036 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003037 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 return 0;
3039
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003040 sk = chan->sk;
3041
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02003042 /* don't delete l2cap channel if sk is owned by user */
3043 if (sock_owned_by_user(sk)) {
Szymon Janc1ec918c2011-11-16 09:32:21 +01003044 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03003045 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02003046 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02003047 bh_unlock_sock(sk);
3048 return 0;
3049 }
3050
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003051 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 bh_unlock_sock(sk);
3053
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003054 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 return 0;
3056}
3057
3058static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3059{
3060 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003061 u16 type;
3062
3063 type = __le16_to_cpu(req->type);
3064
3065 BT_DBG("type 0x%4.4x", type);
3066
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003067 if (type == L2CAP_IT_FEAT_MASK) {
3068 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003069 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003070 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3071 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3072 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003073 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003074 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3075 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003076 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003077 feat_mask |= L2CAP_FEAT_EXT_FLOW
3078 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003079
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003080 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003081 l2cap_send_cmd(conn, cmd->ident,
3082 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003083 } else if (type == L2CAP_IT_FIXED_CHAN) {
3084 u8 buf[12];
3085 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003086
3087 if (enable_hs)
3088 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3089 else
3090 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3091
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003092 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3093 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003094 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003095 l2cap_send_cmd(conn, cmd->ident,
3096 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003097 } else {
3098 struct l2cap_info_rsp rsp;
3099 rsp.type = cpu_to_le16(type);
3100 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3101 l2cap_send_cmd(conn, cmd->ident,
3102 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104
3105 return 0;
3106}
3107
3108static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3109{
3110 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3111 u16 type, result;
3112
3113 type = __le16_to_cpu(rsp->type);
3114 result = __le16_to_cpu(rsp->result);
3115
3116 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3117
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003118 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3119 if (cmd->ident != conn->info_ident ||
3120 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3121 return 0;
3122
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003123 del_timer(&conn->info_timer);
3124
Ville Tervoadb08ed2010-08-04 09:43:33 +03003125 if (result != L2CAP_IR_SUCCESS) {
3126 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3127 conn->info_ident = 0;
3128
3129 l2cap_conn_start(conn);
3130
3131 return 0;
3132 }
3133
Marcel Holtmann984947d2009-02-06 23:35:19 +01003134 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003135 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003136
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003137 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003138 struct l2cap_info_req req;
3139 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3140
3141 conn->info_ident = l2cap_get_ident(conn);
3142
3143 l2cap_send_cmd(conn, conn->info_ident,
3144 L2CAP_INFO_REQ, sizeof(req), &req);
3145 } else {
3146 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3147 conn->info_ident = 0;
3148
3149 l2cap_conn_start(conn);
3150 }
3151 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003152 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003153 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003154
3155 l2cap_conn_start(conn);
3156 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003157
Linus Torvalds1da177e2005-04-16 15:20:36 -07003158 return 0;
3159}
3160
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003161static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3162 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3163 void *data)
3164{
3165 struct l2cap_create_chan_req *req = data;
3166 struct l2cap_create_chan_rsp rsp;
3167 u16 psm, scid;
3168
3169 if (cmd_len != sizeof(*req))
3170 return -EPROTO;
3171
3172 if (!enable_hs)
3173 return -EINVAL;
3174
3175 psm = le16_to_cpu(req->psm);
3176 scid = le16_to_cpu(req->scid);
3177
3178 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3179
3180 /* Placeholder: Always reject */
3181 rsp.dcid = 0;
3182 rsp.scid = cpu_to_le16(scid);
3183 rsp.result = L2CAP_CR_NO_MEM;
3184 rsp.status = L2CAP_CS_NO_INFO;
3185
3186 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3187 sizeof(rsp), &rsp);
3188
3189 return 0;
3190}
3191
3192static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3193 struct l2cap_cmd_hdr *cmd, void *data)
3194{
3195 BT_DBG("conn %p", conn);
3196
3197 return l2cap_connect_rsp(conn, cmd, data);
3198}
3199
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003200static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3201 u16 icid, u16 result)
3202{
3203 struct l2cap_move_chan_rsp rsp;
3204
3205 BT_DBG("icid %d, result %d", icid, result);
3206
3207 rsp.icid = cpu_to_le16(icid);
3208 rsp.result = cpu_to_le16(result);
3209
3210 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3211}
3212
3213static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3214 struct l2cap_chan *chan, u16 icid, u16 result)
3215{
3216 struct l2cap_move_chan_cfm cfm;
3217 u8 ident;
3218
3219 BT_DBG("icid %d, result %d", icid, result);
3220
3221 ident = l2cap_get_ident(conn);
3222 if (chan)
3223 chan->ident = ident;
3224
3225 cfm.icid = cpu_to_le16(icid);
3226 cfm.result = cpu_to_le16(result);
3227
3228 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3229}
3230
3231static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3232 u16 icid)
3233{
3234 struct l2cap_move_chan_cfm_rsp rsp;
3235
3236 BT_DBG("icid %d", icid);
3237
3238 rsp.icid = cpu_to_le16(icid);
3239 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3240}
3241
3242static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3243 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3244{
3245 struct l2cap_move_chan_req *req = data;
3246 u16 icid = 0;
3247 u16 result = L2CAP_MR_NOT_ALLOWED;
3248
3249 if (cmd_len != sizeof(*req))
3250 return -EPROTO;
3251
3252 icid = le16_to_cpu(req->icid);
3253
3254 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3255
3256 if (!enable_hs)
3257 return -EINVAL;
3258
3259 /* Placeholder: Always refuse */
3260 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3261
3262 return 0;
3263}
3264
3265static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3266 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3267{
3268 struct l2cap_move_chan_rsp *rsp = data;
3269 u16 icid, result;
3270
3271 if (cmd_len != sizeof(*rsp))
3272 return -EPROTO;
3273
3274 icid = le16_to_cpu(rsp->icid);
3275 result = le16_to_cpu(rsp->result);
3276
3277 BT_DBG("icid %d, result %d", icid, result);
3278
3279 /* Placeholder: Always unconfirmed */
3280 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3281
3282 return 0;
3283}
3284
3285static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3286 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3287{
3288 struct l2cap_move_chan_cfm *cfm = data;
3289 u16 icid, result;
3290
3291 if (cmd_len != sizeof(*cfm))
3292 return -EPROTO;
3293
3294 icid = le16_to_cpu(cfm->icid);
3295 result = le16_to_cpu(cfm->result);
3296
3297 BT_DBG("icid %d, result %d", icid, result);
3298
3299 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3300
3301 return 0;
3302}
3303
3304static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3305 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3306{
3307 struct l2cap_move_chan_cfm_rsp *rsp = data;
3308 u16 icid;
3309
3310 if (cmd_len != sizeof(*rsp))
3311 return -EPROTO;
3312
3313 icid = le16_to_cpu(rsp->icid);
3314
3315 BT_DBG("icid %d", icid);
3316
3317 return 0;
3318}
3319
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003320static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003321 u16 to_multiplier)
3322{
3323 u16 max_latency;
3324
3325 if (min > max || min < 6 || max > 3200)
3326 return -EINVAL;
3327
3328 if (to_multiplier < 10 || to_multiplier > 3200)
3329 return -EINVAL;
3330
3331 if (max >= to_multiplier * 8)
3332 return -EINVAL;
3333
3334 max_latency = (to_multiplier * 8 / max) - 1;
3335 if (latency > 499 || latency > max_latency)
3336 return -EINVAL;
3337
3338 return 0;
3339}
3340
3341static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3342 struct l2cap_cmd_hdr *cmd, u8 *data)
3343{
3344 struct hci_conn *hcon = conn->hcon;
3345 struct l2cap_conn_param_update_req *req;
3346 struct l2cap_conn_param_update_rsp rsp;
3347 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003348 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003349
3350 if (!(hcon->link_mode & HCI_LM_MASTER))
3351 return -EINVAL;
3352
3353 cmd_len = __le16_to_cpu(cmd->len);
3354 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3355 return -EPROTO;
3356
3357 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003358 min = __le16_to_cpu(req->min);
3359 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003360 latency = __le16_to_cpu(req->latency);
3361 to_multiplier = __le16_to_cpu(req->to_multiplier);
3362
3363 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3364 min, max, latency, to_multiplier);
3365
3366 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003367
3368 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3369 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003370 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3371 else
3372 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3373
3374 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3375 sizeof(rsp), &rsp);
3376
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003377 if (!err)
3378 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3379
Claudio Takahaside731152011-02-11 19:28:55 -02003380 return 0;
3381}
3382
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003383static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3384 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3385{
3386 int err = 0;
3387
3388 switch (cmd->code) {
3389 case L2CAP_COMMAND_REJ:
3390 l2cap_command_rej(conn, cmd, data);
3391 break;
3392
3393 case L2CAP_CONN_REQ:
3394 err = l2cap_connect_req(conn, cmd, data);
3395 break;
3396
3397 case L2CAP_CONN_RSP:
3398 err = l2cap_connect_rsp(conn, cmd, data);
3399 break;
3400
3401 case L2CAP_CONF_REQ:
3402 err = l2cap_config_req(conn, cmd, cmd_len, data);
3403 break;
3404
3405 case L2CAP_CONF_RSP:
3406 err = l2cap_config_rsp(conn, cmd, data);
3407 break;
3408
3409 case L2CAP_DISCONN_REQ:
3410 err = l2cap_disconnect_req(conn, cmd, data);
3411 break;
3412
3413 case L2CAP_DISCONN_RSP:
3414 err = l2cap_disconnect_rsp(conn, cmd, data);
3415 break;
3416
3417 case L2CAP_ECHO_REQ:
3418 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3419 break;
3420
3421 case L2CAP_ECHO_RSP:
3422 break;
3423
3424 case L2CAP_INFO_REQ:
3425 err = l2cap_information_req(conn, cmd, data);
3426 break;
3427
3428 case L2CAP_INFO_RSP:
3429 err = l2cap_information_rsp(conn, cmd, data);
3430 break;
3431
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003432 case L2CAP_CREATE_CHAN_REQ:
3433 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3434 break;
3435
3436 case L2CAP_CREATE_CHAN_RSP:
3437 err = l2cap_create_channel_rsp(conn, cmd, data);
3438 break;
3439
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003440 case L2CAP_MOVE_CHAN_REQ:
3441 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3442 break;
3443
3444 case L2CAP_MOVE_CHAN_RSP:
3445 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3446 break;
3447
3448 case L2CAP_MOVE_CHAN_CFM:
3449 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3450 break;
3451
3452 case L2CAP_MOVE_CHAN_CFM_RSP:
3453 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3454 break;
3455
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003456 default:
3457 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3458 err = -EINVAL;
3459 break;
3460 }
3461
3462 return err;
3463}
3464
3465static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3466 struct l2cap_cmd_hdr *cmd, u8 *data)
3467{
3468 switch (cmd->code) {
3469 case L2CAP_COMMAND_REJ:
3470 return 0;
3471
3472 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003473 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003474
3475 case L2CAP_CONN_PARAM_UPDATE_RSP:
3476 return 0;
3477
3478 default:
3479 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3480 return -EINVAL;
3481 }
3482}
3483
3484static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3485 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486{
3487 u8 *data = skb->data;
3488 int len = skb->len;
3489 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003490 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
3492 l2cap_raw_recv(conn, skb);
3493
3494 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003495 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3497 data += L2CAP_CMD_HDR_SIZE;
3498 len -= L2CAP_CMD_HDR_SIZE;
3499
Al Viro88219a02007-07-29 00:17:25 -07003500 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
Al Viro88219a02007-07-29 00:17:25 -07003502 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 -07003503
Al Viro88219a02007-07-29 00:17:25 -07003504 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 BT_DBG("corrupted command");
3506 break;
3507 }
3508
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003509 if (conn->hcon->type == LE_LINK)
3510 err = l2cap_le_sig_cmd(conn, &cmd, data);
3511 else
3512 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513
3514 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003515 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003516
3517 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
3519 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003520 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3522 }
3523
Al Viro88219a02007-07-29 00:17:25 -07003524 data += cmd_len;
3525 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 }
3527
3528 kfree_skb(skb);
3529}
3530
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003531static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003532{
3533 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003534 int hdr_size;
3535
3536 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3537 hdr_size = L2CAP_EXT_HDR_SIZE;
3538 else
3539 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003540
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003541 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003542 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003543 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3544 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3545
3546 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003547 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003548 }
3549 return 0;
3550}
3551
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003552static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003553{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003554 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003555
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003556 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003557
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003558 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003559
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003560 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003561 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003562 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003563 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003564 }
3565
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003566 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003567 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003568
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003569 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003570
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003571 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003572 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003573 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003574 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003575 }
3576}
3577
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003578static 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 -03003579{
3580 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003581 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003582
3583 bt_cb(skb)->tx_seq = tx_seq;
3584 bt_cb(skb)->sar = sar;
3585
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003586 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003587
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003588 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003589
Szymon Janc039d9572011-11-16 09:32:19 +01003590 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003591 if (bt_cb(next_skb)->tx_seq == tx_seq)
3592 return -EINVAL;
3593
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003594 next_tx_seq_offset = __seq_offset(chan,
3595 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003596
3597 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003598 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003599 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003600 }
3601
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003602 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003603 next_skb = NULL;
3604 else
3605 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3606 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003607
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003608 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003609
3610 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003611}
3612
Mat Martineau84084a32011-07-22 14:54:00 -07003613static void append_skb_frag(struct sk_buff *skb,
3614 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003615{
Mat Martineau84084a32011-07-22 14:54:00 -07003616 /* skb->len reflects data in skb as well as all fragments
3617 * skb->data_len reflects only data in fragments
3618 */
3619 if (!skb_has_frag_list(skb))
3620 skb_shinfo(skb)->frag_list = new_frag;
3621
3622 new_frag->next = NULL;
3623
3624 (*last_frag)->next = new_frag;
3625 *last_frag = new_frag;
3626
3627 skb->len += new_frag->len;
3628 skb->data_len += new_frag->len;
3629 skb->truesize += new_frag->truesize;
3630}
3631
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003632static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003633{
3634 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003635
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003636 switch (__get_ctrl_sar(chan, control)) {
3637 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003638 if (chan->sdu)
3639 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003640
Mat Martineau84084a32011-07-22 14:54:00 -07003641 err = chan->ops->recv(chan->data, skb);
3642 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003643
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003644 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003645 if (chan->sdu)
3646 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003647
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003648 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003649 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003650
Mat Martineau84084a32011-07-22 14:54:00 -07003651 if (chan->sdu_len > chan->imtu) {
3652 err = -EMSGSIZE;
3653 break;
3654 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003655
Mat Martineau84084a32011-07-22 14:54:00 -07003656 if (skb->len >= chan->sdu_len)
3657 break;
3658
3659 chan->sdu = skb;
3660 chan->sdu_last_frag = skb;
3661
3662 skb = NULL;
3663 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003664 break;
3665
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003666 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003667 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003668 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003669
Mat Martineau84084a32011-07-22 14:54:00 -07003670 append_skb_frag(chan->sdu, skb,
3671 &chan->sdu_last_frag);
3672 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003673
Mat Martineau84084a32011-07-22 14:54:00 -07003674 if (chan->sdu->len >= chan->sdu_len)
3675 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003676
Mat Martineau84084a32011-07-22 14:54:00 -07003677 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003678 break;
3679
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003680 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003681 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003682 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003683
Mat Martineau84084a32011-07-22 14:54:00 -07003684 append_skb_frag(chan->sdu, skb,
3685 &chan->sdu_last_frag);
3686 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003687
Mat Martineau84084a32011-07-22 14:54:00 -07003688 if (chan->sdu->len != chan->sdu_len)
3689 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003690
Mat Martineau84084a32011-07-22 14:54:00 -07003691 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003692
Mat Martineau84084a32011-07-22 14:54:00 -07003693 if (!err) {
3694 /* Reassembly complete */
3695 chan->sdu = NULL;
3696 chan->sdu_last_frag = NULL;
3697 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003698 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003699 break;
3700 }
3701
Mat Martineau84084a32011-07-22 14:54:00 -07003702 if (err) {
3703 kfree_skb(skb);
3704 kfree_skb(chan->sdu);
3705 chan->sdu = NULL;
3706 chan->sdu_last_frag = NULL;
3707 chan->sdu_len = 0;
3708 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003709
Mat Martineau84084a32011-07-22 14:54:00 -07003710 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003711}
3712
Mat Martineau26f880d2011-07-07 09:39:01 -07003713static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003714{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003715 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003716
Mat Martineau26f880d2011-07-07 09:39:01 -07003717 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003718
Mat Martineau26f880d2011-07-07 09:39:01 -07003719 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3720
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003721 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003722 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Mat Martineau26f880d2011-07-07 09:39:01 -07003723 l2cap_send_sframe(chan, control);
3724
3725 set_bit(CONN_RNR_SENT, &chan->conn_state);
3726
3727 __clear_ack_timer(chan);
3728}
3729
3730static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3731{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003732 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003733
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003734 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003735 goto done;
3736
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003737 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003738 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003739 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003740 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003741 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003742
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003743 __clear_retrans_timer(chan);
3744 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003745
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003746 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003747
3748done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003749 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3750 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003751
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003752 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003753}
3754
Mat Martineaue3281402011-07-07 09:39:02 -07003755void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003756{
Mat Martineaue3281402011-07-07 09:39:02 -07003757 if (chan->mode == L2CAP_MODE_ERTM) {
3758 if (busy)
3759 l2cap_ertm_enter_local_busy(chan);
3760 else
3761 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003762 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003763}
3764
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003765static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003766{
3767 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003768 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003769
Mat Martineaue3281402011-07-07 09:39:02 -07003770 while ((skb = skb_peek(&chan->srej_q)) &&
3771 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3772 int err;
3773
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003774 if (bt_cb(skb)->tx_seq != tx_seq)
3775 break;
3776
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003777 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003778 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003779 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003780
3781 if (err < 0) {
3782 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3783 break;
3784 }
3785
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003786 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3787 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003788 }
3789}
3790
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003791static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003792{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003793 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003794 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003795
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003796 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003797 if (l->tx_seq == tx_seq) {
3798 list_del(&l->list);
3799 kfree(l);
3800 return;
3801 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003802 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003803 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003804 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003805 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003806 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003807 }
3808}
3809
Szymon Jancaef89f22011-11-16 09:32:18 +01003810static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003811{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003812 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003813 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003814
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003815 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003816 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003817 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003818 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003819
3820 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003821 if (!new)
3822 return -ENOMEM;
3823
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003824 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003825
3826 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3827
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003828 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003829 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003830
3831 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003832
3833 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003834}
3835
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003836static 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 -03003837{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003838 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003839 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003840 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003841 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003842 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003843 int err = 0;
3844
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003845 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 -03003846 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003847
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003848 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003849 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003850 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003851 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003852 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003853 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003854 }
3855
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003856 chan->expected_ack_seq = req_seq;
3857 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003858
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003859 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003860
3861 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003862 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003863 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003864 goto drop;
3865 }
3866
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003867 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003868 goto drop;
3869
Mat Martineau02f1b642011-06-29 14:35:19 -07003870 if (tx_seq == chan->expected_tx_seq)
3871 goto expected;
3872
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003873 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003874 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003875
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003876 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003877 struct srej_list, list);
3878 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003879 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003880 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003881
3882 list_del(&first->list);
3883 kfree(first);
3884
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003885 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003886 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003887 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003888 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003889 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003890 }
3891 } else {
3892 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003893
3894 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003895 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003896 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003897
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003898 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003899 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003900 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003901 return 0;
3902 }
3903 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003904
3905 err = l2cap_send_srejframe(chan, tx_seq);
3906 if (err < 0) {
3907 l2cap_send_disconn_req(chan->conn, chan, -err);
3908 return err;
3909 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003910 }
3911 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003912 expected_tx_seq_offset = __seq_offset(chan,
3913 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003914
3915 /* duplicated tx_seq */
3916 if (tx_seq_offset < expected_tx_seq_offset)
3917 goto drop;
3918
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003919 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003920
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003921 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003922
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003923 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003924 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003925
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003926 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003927 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003928
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003929 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003930
Szymon Jancaef89f22011-11-16 09:32:18 +01003931 err = l2cap_send_srejframe(chan, tx_seq);
3932 if (err < 0) {
3933 l2cap_send_disconn_req(chan->conn, chan, -err);
3934 return err;
3935 }
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003936
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003937 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003938 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003939 return 0;
3940
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003941expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003942 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003943
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003944 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003945 bt_cb(skb)->tx_seq = tx_seq;
3946 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003947 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003948 return 0;
3949 }
3950
Mat Martineau84084a32011-07-22 14:54:00 -07003951 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003952 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
3953
Mat Martineaue3281402011-07-07 09:39:02 -07003954 if (err < 0) {
3955 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3956 return err;
3957 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003958
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003959 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003960 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003961 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003962 }
3963
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003964
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003965 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3966 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003967 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03003968 else
3969 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003970
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003971 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003972
3973drop:
3974 kfree_skb(skb);
3975 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003976}
3977
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003978static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003979{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003980 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003981 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003982
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003983 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003984 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003985
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003986 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003987 set_bit(CONN_SEND_FBIT, &chan->conn_state);
3988 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
3989 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003990 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003991 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003992
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003993 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003994 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003995 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003996 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003997 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003998
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003999 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004000 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004001
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004002 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004003 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004004
4005 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004006 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004007 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004008 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004009
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004010 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4011 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004012 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004013 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004014 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004015 }
4016}
4017
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004018static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004019{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004020 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004021
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004022 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004023
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004024 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004025
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004026 chan->expected_ack_seq = tx_seq;
4027 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004028
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004029 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004030 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004031 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004032 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004033 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004034
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004035 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4036 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004037 }
4038}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004039static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004040{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004041 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004042
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004043 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004044
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004045 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004046
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004047 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004048 chan->expected_ack_seq = tx_seq;
4049 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004050
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004051 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004052 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004053
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004054 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004055
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004056 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004057 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004058 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004059 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004060 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004061 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004062 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004063 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004064 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004065 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004066 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004067 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004068 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004069 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004070 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004071 }
4072 }
4073}
4074
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004075static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004076{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004077 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004078
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004079 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004080
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004081 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004082 chan->expected_ack_seq = tx_seq;
4083 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004084
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004085 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004086 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004087
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004088 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004089 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004090 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004091 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004092 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004093 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004094
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004095 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004096 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004097 } else {
4098 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4099 l2cap_send_sframe(chan, rx_control);
4100 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004101}
4102
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004103static 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 -03004104{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004105 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -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 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004109 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004110 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004111 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004112 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004113 }
4114
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004115 switch (__get_ctrl_super(chan, rx_control)) {
4116 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004117 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004118 break;
4119
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004120 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004121 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004122 break;
4123
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004124 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004125 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004126 break;
4127
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004128 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004129 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004130 break;
4131 }
4132
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004133 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004134 return 0;
4135}
4136
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004137static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
4138{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004139 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004140 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004141 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004142 int len, next_tx_seq_offset, req_seq_offset;
4143
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004144 control = __get_control(chan, skb->data);
4145 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004146 len = skb->len;
4147
4148 /*
4149 * We can just drop the corrupted I-frame here.
4150 * Receiver will miss it and start proper recovery
4151 * procedures and ask retransmission.
4152 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004153 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004154 goto drop;
4155
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004156 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004157 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004158
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004159 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004160 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004161
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004162 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004163 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004164 goto drop;
4165 }
4166
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004167 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004168
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004169 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4170
4171 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4172 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004173
4174 /* check for invalid req-seq */
4175 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004176 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004177 goto drop;
4178 }
4179
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004180 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004181 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004182 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004183 goto drop;
4184 }
4185
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004186 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004187 } else {
4188 if (len != 0) {
4189 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004190 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004191 goto drop;
4192 }
4193
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004194 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004195 }
4196
4197 return 0;
4198
4199drop:
4200 kfree_skb(skb);
4201 return 0;
4202}
4203
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4205{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004206 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07004207 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004208 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004209 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004210 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004212 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004213 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214 BT_DBG("unknown cid 0x%4.4x", cid);
4215 goto drop;
4216 }
4217
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004218 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004219
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004220 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004222 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 goto drop;
4224
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004225 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004226 case L2CAP_MODE_BASIC:
4227 /* If socket recv buffers overflows we drop data here
4228 * which is *bad* because L2CAP has to be reliable.
4229 * But we don't have any other choice. L2CAP doesn't
4230 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004232 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004233 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004235 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004236 goto done;
4237 break;
4238
4239 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004240 if (!sock_owned_by_user(sk)) {
4241 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004242 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004243 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004244 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004245 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004246
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004247 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004248
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004249 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004250 control = __get_control(chan, skb->data);
4251 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004252 len = skb->len;
4253
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004254 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004255 goto drop;
4256
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004257 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004258 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004259
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004260 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004261 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004262
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004263 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004264 goto drop;
4265
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004266 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004267
Mat Martineau84084a32011-07-22 14:54:00 -07004268 if (chan->expected_tx_seq != tx_seq) {
4269 /* Frame(s) missing - must discard partial SDU */
4270 kfree_skb(chan->sdu);
4271 chan->sdu = NULL;
4272 chan->sdu_last_frag = NULL;
4273 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004274
Mat Martineau84084a32011-07-22 14:54:00 -07004275 /* TODO: Notify userland of missing data */
4276 }
4277
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004278 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004279
4280 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4281 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004282
4283 goto done;
4284
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004285 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004286 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004287 break;
4288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289
4290drop:
4291 kfree_skb(skb);
4292
4293done:
Marcel Holtmann01394182006-07-03 10:02:46 +02004294 if (sk)
4295 bh_unlock_sock(sk);
4296
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297 return 0;
4298}
4299
Al Viro8e036fc2007-07-29 00:16:36 -07004300static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004302 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004303 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004305 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4306 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 goto drop;
4308
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004309 sk = chan->sk;
4310
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00004311 bh_lock_sock(sk);
4312
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 BT_DBG("sk %p, len %d", sk, skb->len);
4314
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004315 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 goto drop;
4317
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004318 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 goto drop;
4320
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004321 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 goto done;
4323
4324drop:
4325 kfree_skb(skb);
4326
4327done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004328 if (sk)
4329 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 return 0;
4331}
4332
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004333static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4334{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004335 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004336 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004337
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004338 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4339 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004340 goto drop;
4341
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004342 sk = chan->sk;
4343
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004344 bh_lock_sock(sk);
4345
4346 BT_DBG("sk %p, len %d", sk, skb->len);
4347
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004348 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004349 goto drop;
4350
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004351 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004352 goto drop;
4353
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004354 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004355 goto done;
4356
4357drop:
4358 kfree_skb(skb);
4359
4360done:
4361 if (sk)
4362 bh_unlock_sock(sk);
4363 return 0;
4364}
4365
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4367{
4368 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004369 u16 cid, len;
4370 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371
4372 skb_pull(skb, L2CAP_HDR_SIZE);
4373 cid = __le16_to_cpu(lh->cid);
4374 len = __le16_to_cpu(lh->len);
4375
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004376 if (len != skb->len) {
4377 kfree_skb(skb);
4378 return;
4379 }
4380
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4382
4383 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004384 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004385 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 l2cap_sig_channel(conn, skb);
4387 break;
4388
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004389 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004390 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 skb_pull(skb, 2);
4392 l2cap_conless_channel(conn, psm, skb);
4393 break;
4394
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004395 case L2CAP_CID_LE_DATA:
4396 l2cap_att_channel(conn, cid, skb);
4397 break;
4398
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004399 case L2CAP_CID_SMP:
4400 if (smp_sig_channel(conn, skb))
4401 l2cap_conn_del(conn->hcon, EACCES);
4402 break;
4403
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 default:
4405 l2cap_data_channel(conn, cid, skb);
4406 break;
4407 }
4408}
4409
4410/* ---- L2CAP interface with lower layer (HCI) ---- */
4411
4412static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4413{
4414 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004415 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416
4417 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004418 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419
4420 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4421
4422 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004423 read_lock(&chan_list_lock);
4424 list_for_each_entry(c, &chan_list, global_l) {
4425 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004426
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004427 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 continue;
4429
4430 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004431 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004432 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004433 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004435 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4436 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004437 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004438 lm2 |= HCI_LM_MASTER;
4439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004440 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004441 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442
4443 return exact ? lm1 : lm2;
4444}
4445
4446static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4447{
Marcel Holtmann01394182006-07-03 10:02:46 +02004448 struct l2cap_conn *conn;
4449
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4451
Ville Tervoacd7d372011-02-10 22:38:49 -03004452 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004453 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
4455 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 conn = l2cap_conn_add(hcon, status);
4457 if (conn)
4458 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004459 } else
Joe Perchese1750722011-06-29 18:18:29 -07004460 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461
4462 return 0;
4463}
4464
Marcel Holtmann2950f212009-02-12 14:02:50 +01004465static int l2cap_disconn_ind(struct hci_conn *hcon)
4466{
4467 struct l2cap_conn *conn = hcon->l2cap_data;
4468
4469 BT_DBG("hcon %p", hcon);
4470
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004471 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004472 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004473
4474 return conn->disc_reason;
4475}
4476
4477static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478{
4479 BT_DBG("hcon %p reason %d", hcon, reason);
4480
Ville Tervoacd7d372011-02-10 22:38:49 -03004481 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004482 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483
Joe Perchese1750722011-06-29 18:18:29 -07004484 l2cap_conn_del(hcon, bt_to_errno(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004485
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 return 0;
4487}
4488
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004489static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004490{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004491 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004492 return;
4493
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004494 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004495 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004496 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004497 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004498 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004499 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004500 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004501 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004502 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004503 }
4504}
4505
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004506static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004508 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004509 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510
Marcel Holtmann01394182006-07-03 10:02:46 +02004511 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004513
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 BT_DBG("conn %p", conn);
4515
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004516 if (hcon->type == LE_LINK) {
4517 smp_distribute_keys(conn, 0);
4518 del_timer(&conn->security_timer);
4519 }
4520
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004521 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004523 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004524 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004525
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 bh_lock_sock(sk);
4527
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004528 BT_DBG("chan->scid %d", chan->scid);
4529
4530 if (chan->scid == L2CAP_CID_LE_DATA) {
4531 if (!status && encrypt) {
4532 chan->sec_level = hcon->sec_level;
4533 l2cap_chan_ready(sk);
4534 }
4535
4536 bh_unlock_sock(sk);
4537 continue;
4538 }
4539
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004540 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004541 bh_unlock_sock(sk);
4542 continue;
4543 }
4544
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004545 if (!status && (chan->state == BT_CONNECTED ||
4546 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004547 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004548 bh_unlock_sock(sk);
4549 continue;
4550 }
4551
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004552 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004553 if (!status) {
4554 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004555 req.scid = cpu_to_le16(chan->scid);
4556 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004557
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004558 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004559 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004560
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004561 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004562 L2CAP_CONN_REQ, sizeof(req), &req);
4563 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004564 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004565 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004566 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004567 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004568 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004569 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004570
4571 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004572 if (bt_sk(sk)->defer_setup) {
4573 struct sock *parent = bt_sk(sk)->parent;
4574 res = L2CAP_CR_PEND;
4575 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004576 if (parent)
4577 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004578 } else {
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004579 l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004580 res = L2CAP_CR_SUCCESS;
4581 stat = L2CAP_CS_NO_INFO;
4582 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004583 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004584 l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004585 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004586 res = L2CAP_CR_SEC_BLOCK;
4587 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004588 }
4589
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004590 rsp.scid = cpu_to_le16(chan->dcid);
4591 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004592 rsp.result = cpu_to_le16(res);
4593 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004594 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4595 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 }
4597
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 bh_unlock_sock(sk);
4599 }
4600
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004601 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004602
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603 return 0;
4604}
4605
4606static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4607{
4608 struct l2cap_conn *conn = hcon->l2cap_data;
4609
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004610 if (!conn)
4611 conn = l2cap_conn_add(hcon, 0);
4612
4613 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 goto drop;
4615
4616 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4617
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004618 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004620 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004621 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 int len;
4623
4624 if (conn->rx_len) {
4625 BT_ERR("Unexpected start frame (len %d)", skb->len);
4626 kfree_skb(conn->rx_skb);
4627 conn->rx_skb = NULL;
4628 conn->rx_len = 0;
4629 l2cap_conn_unreliable(conn, ECOMM);
4630 }
4631
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004632 /* Start fragment always begin with Basic L2CAP header */
4633 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004634 BT_ERR("Frame is too short (len %d)", skb->len);
4635 l2cap_conn_unreliable(conn, ECOMM);
4636 goto drop;
4637 }
4638
4639 hdr = (struct l2cap_hdr *) skb->data;
4640 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004641 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642
4643 if (len == skb->len) {
4644 /* Complete frame received */
4645 l2cap_recv_frame(conn, skb);
4646 return 0;
4647 }
4648
4649 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4650
4651 if (skb->len > len) {
4652 BT_ERR("Frame is too long (len %d, expected len %d)",
4653 skb->len, len);
4654 l2cap_conn_unreliable(conn, ECOMM);
4655 goto drop;
4656 }
4657
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004658 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004659
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004660 if (chan && chan->sk) {
4661 struct sock *sk = chan->sk;
4662
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004663 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004664 BT_ERR("Frame exceeding recv MTU (len %d, "
4665 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004666 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004667 bh_unlock_sock(sk);
4668 l2cap_conn_unreliable(conn, ECOMM);
4669 goto drop;
4670 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004671 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004672 }
4673
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004675 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4676 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004677 goto drop;
4678
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004679 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004680 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 conn->rx_len = len - skb->len;
4682 } else {
4683 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4684
4685 if (!conn->rx_len) {
4686 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4687 l2cap_conn_unreliable(conn, ECOMM);
4688 goto drop;
4689 }
4690
4691 if (skb->len > conn->rx_len) {
4692 BT_ERR("Fragment is too long (len %d, expected %d)",
4693 skb->len, conn->rx_len);
4694 kfree_skb(conn->rx_skb);
4695 conn->rx_skb = NULL;
4696 conn->rx_len = 0;
4697 l2cap_conn_unreliable(conn, ECOMM);
4698 goto drop;
4699 }
4700
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004701 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004702 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 conn->rx_len -= skb->len;
4704
4705 if (!conn->rx_len) {
4706 /* Complete frame received */
4707 l2cap_recv_frame(conn, conn->rx_skb);
4708 conn->rx_skb = NULL;
4709 }
4710 }
4711
4712drop:
4713 kfree_skb(skb);
4714 return 0;
4715}
4716
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004717static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004719 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004721 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004723 list_for_each_entry(c, &chan_list, global_l) {
4724 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004726 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 +01004727 batostr(&bt_sk(sk)->src),
4728 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004729 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004730 c->scid, c->dcid, c->imtu, c->omtu,
4731 c->sec_level, c->mode);
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004732}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004734 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004735
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004736 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737}
4738
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004739static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4740{
4741 return single_open(file, l2cap_debugfs_show, inode->i_private);
4742}
4743
4744static const struct file_operations l2cap_debugfs_fops = {
4745 .open = l2cap_debugfs_open,
4746 .read = seq_read,
4747 .llseek = seq_lseek,
4748 .release = single_release,
4749};
4750
4751static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753static struct hci_proto l2cap_hci_proto = {
4754 .name = "L2CAP",
4755 .id = HCI_PROTO_L2CAP,
4756 .connect_ind = l2cap_connect_ind,
4757 .connect_cfm = l2cap_connect_cfm,
4758 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004759 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004760 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 .recv_acldata = l2cap_recv_acldata
4762};
4763
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004764int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765{
4766 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004767
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004768 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 if (err < 0)
4770 return err;
4771
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 err = hci_register_proto(&l2cap_hci_proto);
4773 if (err < 0) {
4774 BT_ERR("L2CAP protocol registration failed");
4775 bt_sock_unregister(BTPROTO_L2CAP);
4776 goto error;
4777 }
4778
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004779 if (bt_debugfs) {
4780 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4781 bt_debugfs, NULL, &l2cap_debugfs_fops);
4782 if (!l2cap_debugfs)
4783 BT_ERR("Failed to create L2CAP debug file");
4784 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785
Linus Torvalds1da177e2005-04-16 15:20:36 -07004786 return 0;
4787
4788error:
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004789 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 return err;
4791}
4792
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004793void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004795 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4798 BT_ERR("L2CAP protocol unregistration failed");
4799
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004800 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801}
4802
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004803module_param(disable_ertm, bool, 0644);
4804MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");