blob: a898285e3ea63b8560e418308ed65a96fd6e6b0f [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Gustavo F. Padovan590051d2011-12-18 13:39:33 -02006 Copyright (C) 2011 ProFUSION Embedded Systems
Linus Torvalds1da177e2005-04-16 15:20:36 -07007
8 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation;
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
17 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090023 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 SOFTWARE IS DISCLAIMED.
26*/
27
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020028/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31
32#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080033#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/errno.h>
35#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/sched.h>
37#include <linux/slab.h>
38#include <linux/poll.h>
39#include <linux/fcntl.h>
40#include <linux/init.h>
41#include <linux/interrupt.h>
42#include <linux/socket.h>
43#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080045#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010046#include <linux/debugfs.h>
47#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030048#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030049#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <net/sock.h>
51
52#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <asm/unaligned.h>
54
55#include <net/bluetooth/bluetooth.h>
56#include <net/bluetooth/hci_core.h>
57#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030058#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020060int disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020061
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070062static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070063static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Johannes Bergb5ad8b72011-06-01 08:54:45 +020065static LIST_HEAD(chan_list);
66static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
69 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030070static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
71 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030072static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030073static void l2cap_send_disconn_req(struct l2cap_conn *conn,
74 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030076static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
77
Marcel Holtmann01394182006-07-03 10:02:46 +020078/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030079
80static inline void chan_hold(struct l2cap_chan *c)
81{
82 atomic_inc(&c->refcnt);
83}
84
85static inline void chan_put(struct l2cap_chan *c)
86{
87 if (atomic_dec_and_test(&c->refcnt))
88 kfree(c);
89}
90
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030091static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020092{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020093 struct l2cap_chan *c, *r = NULL;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030094
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020095 rcu_read_lock();
96
97 list_for_each_entry_rcu(c, &conn->chan_l, list) {
98 if (c->dcid == cid) {
99 r = c;
100 break;
101 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200102 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200103
104 rcu_read_unlock();
105 return r;
Marcel Holtmann01394182006-07-03 10:02:46 +0200106}
107
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300108static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200109{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200110 struct l2cap_chan *c, *r = NULL;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300111
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200112 rcu_read_lock();
113
114 list_for_each_entry_rcu(c, &conn->chan_l, list) {
115 if (c->scid == cid) {
116 r = c;
117 break;
118 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200119 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200120
121 rcu_read_unlock();
122 return r;
Marcel Holtmann01394182006-07-03 10:02:46 +0200123}
124
125/* Find channel with given SCID.
126 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300127static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200128{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300129 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300130
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300131 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300132 if (c)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300133 lock_sock(c->sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300134 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200135}
136
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300137static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200138{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200139 struct l2cap_chan *c, *r = NULL;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300140
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200141 rcu_read_lock();
142
143 list_for_each_entry_rcu(c, &conn->chan_l, list) {
144 if (c->ident == ident) {
145 r = c;
146 break;
147 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200148 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200149
150 rcu_read_unlock();
151 return r;
Marcel Holtmann01394182006-07-03 10:02:46 +0200152}
153
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300154static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200155{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300156 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300157
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300158 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300159 if (c)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300160 lock_sock(c->sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300161 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200162}
163
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300164static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300165{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300166 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300167
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300168 list_for_each_entry(c, &chan_list, global_l) {
169 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100170 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300171 }
Szymon Janc250938c2011-11-16 09:32:22 +0100172 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300173}
174
175int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
176{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300177 int err;
178
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300179 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300180
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300181 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300182 err = -EADDRINUSE;
183 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300184 }
185
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300186 if (psm) {
187 chan->psm = psm;
188 chan->sport = psm;
189 err = 0;
190 } else {
191 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300192
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300193 err = -EINVAL;
194 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300195 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300196 chan->psm = cpu_to_le16(p);
197 chan->sport = cpu_to_le16(p);
198 err = 0;
199 break;
200 }
201 }
202
203done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300204 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300205 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300206}
207
208int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
209{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300210 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300211
212 chan->scid = scid;
213
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300214 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300215
216 return 0;
217}
218
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300219static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200220{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300221 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200222
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300223 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300224 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200225 return cid;
226 }
227
228 return 0;
229}
230
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200231static char *state_to_string(int state)
232{
233 switch(state) {
234 case BT_CONNECTED:
235 return "BT_CONNECTED";
236 case BT_OPEN:
237 return "BT_OPEN";
238 case BT_BOUND:
239 return "BT_BOUND";
240 case BT_LISTEN:
241 return "BT_LISTEN";
242 case BT_CONNECT:
243 return "BT_CONNECT";
244 case BT_CONNECT2:
245 return "BT_CONNECT2";
246 case BT_CONFIG:
247 return "BT_CONFIG";
248 case BT_DISCONN:
249 return "BT_DISCONN";
250 case BT_CLOSED:
251 return "BT_CLOSED";
252 }
253
254 return "invalid state";
255}
256
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300257static void l2cap_state_change(struct l2cap_chan *chan, int state)
258{
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200259 BT_DBG("%p %s -> %s", chan, state_to_string(chan->state),
260 state_to_string(state));
261
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300262 chan->state = state;
263 chan->ops->state_change(chan->data, state);
264}
265
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300266static void l2cap_chan_timeout(struct work_struct *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300267{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300268 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
269 chan_timer.work);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300270 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
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300275 lock_sock(sk);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300276
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300277 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300278 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300279 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300280 chan->sec_level != BT_SECURITY_SDP)
281 reason = ECONNREFUSED;
282 else
283 reason = ETIMEDOUT;
284
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300285 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300286
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300287 release_sock(sk);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300288
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300289 chan->ops->close(chan->data);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300290 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300291}
292
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300293struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200294{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300295 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200296
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300297 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
298 if (!chan)
299 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200300
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300301 chan->sk = sk;
302
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300303 write_lock_bh(&chan_list_lock);
304 list_add(&chan->global_l, &chan_list);
305 write_unlock_bh(&chan_list_lock);
306
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300307 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300308
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300309 chan->state = BT_OPEN;
310
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300311 atomic_set(&chan->refcnt, 1);
312
Szymon Jancabc545b2011-11-03 16:05:44 +0100313 BT_DBG("sk %p chan %p", sk, chan);
314
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300315 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200316}
317
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300318void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300319{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300320 write_lock_bh(&chan_list_lock);
321 list_del(&chan->global_l);
322 write_unlock_bh(&chan_list_lock);
323
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300324 chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300325}
326
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200327static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200328{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300329 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300330 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200331
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200332 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100333
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300334 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200335
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300336 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300337 if (conn->hcon->type == LE_LINK) {
338 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300339 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300340 chan->scid = L2CAP_CID_LE_DATA;
341 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300342 } else {
343 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300344 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300345 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300346 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300347 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200348 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300349 chan->scid = L2CAP_CID_CONN_LESS;
350 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300351 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200352 } else {
353 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300354 chan->scid = L2CAP_CID_SIGNALING;
355 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300356 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200357 }
358
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300359 chan->local_id = L2CAP_BESTEFFORT_ID;
360 chan->local_stype = L2CAP_SERV_BESTEFFORT;
361 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
362 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
363 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
364 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
365
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300366 chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300367
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200368 list_add_rcu(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200369}
370
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900371/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200372 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300373static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200374{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300375 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300376 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200377 struct sock *parent = bt_sk(sk)->parent;
378
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300379 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200380
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300381 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200382
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900383 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300384 /* Delete from channel list */
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200385 list_del_rcu(&chan->list);
386 synchronize_rcu();
387
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300388 chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300389
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300390 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200391 hci_conn_put(conn->hcon);
392 }
393
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300394 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200395 sock_set_flag(sk, SOCK_ZAPPED);
396
397 if (err)
398 sk->sk_err = err;
399
400 if (parent) {
401 bt_accept_unlink(sk);
402 parent->sk_data_ready(parent, 0);
403 } else
404 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300405
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300406 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
407 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300408 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300409
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300410 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300411
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300412 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300413 struct srej_list *l, *tmp;
414
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300415 __clear_retrans_timer(chan);
416 __clear_monitor_timer(chan);
417 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300418
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300419 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300420
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300421 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300422 list_del(&l->list);
423 kfree(l);
424 }
425 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200426}
427
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300428static void l2cap_chan_cleanup_listen(struct sock *parent)
429{
430 struct sock *sk;
431
432 BT_DBG("parent %p", parent);
433
434 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300435 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300436 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300437 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300438 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300439 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300440 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300441 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300442 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300443}
444
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300445void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300446{
447 struct l2cap_conn *conn = chan->conn;
448 struct sock *sk = chan->sk;
449
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300450 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300451
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300452 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300453 case BT_LISTEN:
454 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300455
456 l2cap_state_change(chan, BT_CLOSED);
457 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300458 break;
459
460 case BT_CONNECTED:
461 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300462 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300463 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300464 __clear_chan_timer(chan);
465 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300466 l2cap_send_disconn_req(conn, chan, reason);
467 } else
468 l2cap_chan_del(chan, reason);
469 break;
470
471 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300472 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300473 conn->hcon->type == ACL_LINK) {
474 struct l2cap_conn_rsp rsp;
475 __u16 result;
476
477 if (bt_sk(sk)->defer_setup)
478 result = L2CAP_CR_SEC_BLOCK;
479 else
480 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300481 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300482
483 rsp.scid = cpu_to_le16(chan->dcid);
484 rsp.dcid = cpu_to_le16(chan->scid);
485 rsp.result = cpu_to_le16(result);
486 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
487 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
488 sizeof(rsp), &rsp);
489 }
490
491 l2cap_chan_del(chan, reason);
492 break;
493
494 case BT_CONNECT:
495 case BT_DISCONN:
496 l2cap_chan_del(chan, reason);
497 break;
498
499 default:
500 sock_set_flag(sk, SOCK_ZAPPED);
501 break;
502 }
503}
504
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300505static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530506{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300507 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300508 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530509 case BT_SECURITY_HIGH:
510 return HCI_AT_DEDICATED_BONDING_MITM;
511 case BT_SECURITY_MEDIUM:
512 return HCI_AT_DEDICATED_BONDING;
513 default:
514 return HCI_AT_NO_BONDING;
515 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300516 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300517 if (chan->sec_level == BT_SECURITY_LOW)
518 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530519
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300520 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530521 return HCI_AT_NO_BONDING_MITM;
522 else
523 return HCI_AT_NO_BONDING;
524 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300525 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530526 case BT_SECURITY_HIGH:
527 return HCI_AT_GENERAL_BONDING_MITM;
528 case BT_SECURITY_MEDIUM:
529 return HCI_AT_GENERAL_BONDING;
530 default:
531 return HCI_AT_NO_BONDING;
532 }
533 }
534}
535
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200536/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200537int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200538{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300539 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100540 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200541
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300542 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100543
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300544 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200545}
546
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200547static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200548{
549 u8 id;
550
551 /* Get next available identificator.
552 * 1 - 128 are used by kernel.
553 * 129 - 199 are reserved.
554 * 200 - 254 are used by utilities like l2ping, etc.
555 */
556
557 spin_lock_bh(&conn->lock);
558
559 if (++conn->tx_ident > 128)
560 conn->tx_ident = 1;
561
562 id = conn->tx_ident;
563
564 spin_unlock_bh(&conn->lock);
565
566 return id;
567}
568
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300569static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200570{
571 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200572 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200573
574 BT_DBG("code 0x%2.2x", code);
575
576 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300577 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200578
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200579 if (lmp_no_flush_capable(conn->hcon->hdev))
580 flags = ACL_START_NO_FLUSH;
581 else
582 flags = ACL_START;
583
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700584 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200585 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700586
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200587 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200588}
589
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200590static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
591{
592 struct hci_conn *hcon = chan->conn->hcon;
593 u16 flags;
594
595 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
596 skb->priority);
597
598 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
599 lmp_no_flush_capable(hcon->hdev))
600 flags = ACL_START_NO_FLUSH;
601 else
602 flags = ACL_START;
603
604 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
605 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
607
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300608static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300609{
610 struct sk_buff *skb;
611 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300612 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300613 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300614
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300615 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300616 return;
617
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300618 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
619 hlen = L2CAP_EXT_HDR_SIZE;
620 else
621 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300622
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300623 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300624 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300625
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300626 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300627
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300628 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300629
630 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300631
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300632 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300633 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300634
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300635 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300636 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300637
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300638 skb = bt_skb_alloc(count, GFP_ATOMIC);
639 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300640 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300641
642 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300643 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300644 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300645
646 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300647
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300648 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300649 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
650 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300651 }
652
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200653 skb->priority = HCI_PRIO_MAX;
654 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300655}
656
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300657static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300658{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300659 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300660 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300661 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300662 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300663 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300664
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300665 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300666
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300667 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300668}
669
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300670static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300671{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300672 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300673}
674
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300675static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200676{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300677 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200678
679 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100680 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
681 return;
682
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200683 if (l2cap_chan_check_security(chan) &&
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300684 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200685 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300686 req.scid = cpu_to_le16(chan->scid);
687 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200688
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300689 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300690 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200691
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300692 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
693 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200694 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200695 } else {
696 struct l2cap_info_req req;
697 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
698
699 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
700 conn->info_ident = l2cap_get_ident(conn);
701
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200702 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200703 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
704
705 l2cap_send_cmd(conn, conn->info_ident,
706 L2CAP_INFO_REQ, sizeof(req), &req);
707 }
708}
709
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300710static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
711{
712 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300713 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300714 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
715
716 switch (mode) {
717 case L2CAP_MODE_ERTM:
718 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
719 case L2CAP_MODE_STREAMING:
720 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
721 default:
722 return 0x00;
723 }
724}
725
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300726static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300727{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300728 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300729 struct l2cap_disconn_req req;
730
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300731 if (!conn)
732 return;
733
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300734 sk = chan->sk;
735
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300736 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300737 __clear_retrans_timer(chan);
738 __clear_monitor_timer(chan);
739 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300740 }
741
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300742 req.dcid = cpu_to_le16(chan->dcid);
743 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300744 l2cap_send_cmd(conn, l2cap_get_ident(conn),
745 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300746
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300747 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300748 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300749}
750
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200752static void l2cap_conn_start(struct l2cap_conn *conn)
753{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200754 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200755
756 BT_DBG("conn %p", conn);
757
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200758 rcu_read_lock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200759
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200760 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300761 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300762
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200763 bh_lock_sock(sk);
764
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300765 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200766 bh_unlock_sock(sk);
767 continue;
768 }
769
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300770 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300771 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300772
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200773 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300774 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300775 bh_unlock_sock(sk);
776 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200777 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300778
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300779 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
780 && test_bit(CONF_STATE2_DEVICE,
781 &chan->conf_state)) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300782 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300783 * so release the lock */
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300784 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300785 bh_unlock_sock(sk);
786 continue;
787 }
788
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300789 req.scid = cpu_to_le16(chan->scid);
790 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300791
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300792 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300793 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300794
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300795 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
796 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300797
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300798 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200799 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300800 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300801 rsp.scid = cpu_to_le16(chan->dcid);
802 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200803
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200804 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100805 if (bt_sk(sk)->defer_setup) {
806 struct sock *parent = bt_sk(sk)->parent;
807 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
808 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000809 if (parent)
810 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100811
812 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300813 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100814 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
815 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
816 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200817 } else {
818 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
819 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
820 }
821
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300822 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
823 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300824
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300825 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300826 rsp.result != L2CAP_CR_SUCCESS) {
827 bh_unlock_sock(sk);
828 continue;
829 }
830
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300831 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300832 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300833 l2cap_build_conf_req(chan, buf), buf);
834 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200835 }
836
837 bh_unlock_sock(sk);
838 }
839
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200840 rcu_read_unlock();
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200841}
842
Ville Tervob62f3282011-02-10 22:38:50 -0300843/* Find socket with cid and source bdaddr.
844 * Returns closest match, locked.
845 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300846static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300847{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300848 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300849
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300850 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300851
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300852 list_for_each_entry(c, &chan_list, global_l) {
853 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300854
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300855 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300856 continue;
857
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300858 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300859 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300860 if (!bacmp(&bt_sk(sk)->src, src)) {
861 read_unlock(&chan_list_lock);
862 return c;
863 }
Ville Tervob62f3282011-02-10 22:38:50 -0300864
865 /* Closest match */
866 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300867 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300868 }
869 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300870
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300871 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300872
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300873 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300874}
875
876static void l2cap_le_conn_ready(struct l2cap_conn *conn)
877{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300878 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300879 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300880
881 BT_DBG("");
882
883 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300884 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300885 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300886 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300887 return;
888
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300889 parent = pchan->sk;
890
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300891 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300892
Ville Tervob62f3282011-02-10 22:38:50 -0300893 /* Check for backlog size */
894 if (sk_acceptq_is_full(parent)) {
895 BT_DBG("backlog full %d", parent->sk_ack_backlog);
896 goto clean;
897 }
898
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300899 chan = pchan->ops->new_connection(pchan->data);
900 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300901 goto clean;
902
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300903 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300904
Ville Tervob62f3282011-02-10 22:38:50 -0300905 hci_conn_hold(conn->hcon);
906
Ville Tervob62f3282011-02-10 22:38:50 -0300907 bacpy(&bt_sk(sk)->src, conn->src);
908 bacpy(&bt_sk(sk)->dst, conn->dst);
909
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300910 bt_accept_enqueue(parent, sk);
911
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200912 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300913
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300914 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300915
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300916 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300917 parent->sk_data_ready(parent, 0);
918
Ville Tervob62f3282011-02-10 22:38:50 -0300919clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300920 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300921}
922
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300923static void l2cap_chan_ready(struct sock *sk)
924{
925 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
926 struct sock *parent = bt_sk(sk)->parent;
927
928 BT_DBG("sk %p, parent %p", sk, parent);
929
930 chan->conf_state = 0;
931 __clear_chan_timer(chan);
932
Vinicius Costa Gomes43f3dc42011-06-20 18:53:18 -0300933 l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300934 sk->sk_state_change(sk);
935
936 if (parent)
937 parent->sk_data_ready(parent, 0);
938}
939
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200940static void l2cap_conn_ready(struct l2cap_conn *conn)
941{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300942 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200943
944 BT_DBG("conn %p", conn);
945
Ville Tervob62f3282011-02-10 22:38:50 -0300946 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
947 l2cap_le_conn_ready(conn);
948
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300949 if (conn->hcon->out && conn->hcon->type == LE_LINK)
950 smp_conn_security(conn, conn->hcon->pending_sec_level);
951
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200952 rcu_read_lock();
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200953
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200954 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300955 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300956
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200957 bh_lock_sock(sk);
958
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300959 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300960 if (smp_conn_security(conn, chan->sec_level))
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300961 l2cap_chan_ready(sk);
Ville Tervoacd7d372011-02-10 22:38:49 -0300962
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300963 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300964 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300965 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200966 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300967
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300968 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300969 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200970
971 bh_unlock_sock(sk);
972 }
973
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200974 rcu_read_unlock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200975}
976
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200977/* Notify sockets that we cannot guaranty reliability anymore */
978static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
979{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300980 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200981
982 BT_DBG("conn %p", conn);
983
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200984 rcu_read_lock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200985
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200986 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300987 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300988
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300989 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200990 sk->sk_err = err;
991 }
992
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200993 rcu_read_unlock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200994}
995
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200996static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200997{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200998 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200999 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001000
Marcel Holtmann984947d2009-02-06 23:35:19 +01001001 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01001002 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01001003
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001004 l2cap_conn_start(conn);
1005}
1006
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001007static void l2cap_conn_del(struct hci_conn *hcon, int err)
1008{
1009 struct l2cap_conn *conn = hcon->l2cap_data;
1010 struct l2cap_chan *chan, *l;
1011 struct sock *sk;
1012
1013 if (!conn)
1014 return;
1015
1016 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1017
1018 kfree_skb(conn->rx_skb);
1019
1020 /* Kill channels */
1021 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
1022 sk = chan->sk;
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03001023 lock_sock(sk);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001024 l2cap_chan_del(chan, err);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03001025 release_sock(sk);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001026 chan->ops->close(chan->data);
1027 }
1028
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001029 hci_chan_del(conn->hchan);
1030
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001031 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001032 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001033
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001034 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001035 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001036 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001037 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001038
1039 hcon->l2cap_data = NULL;
1040 kfree(conn);
1041}
1042
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001043static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001044{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001045 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1046 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001047
1048 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1049}
1050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1052{
Marcel Holtmann01394182006-07-03 10:02:46 +02001053 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001054 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055
Marcel Holtmann01394182006-07-03 10:02:46 +02001056 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 return conn;
1058
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001059 hchan = hci_chan_create(hcon);
1060 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001063 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1064 if (!conn) {
1065 hci_chan_del(hchan);
1066 return NULL;
1067 }
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 hcon->l2cap_data = conn;
1070 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001071 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001073 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001074
Ville Tervoacd7d372011-02-10 22:38:49 -03001075 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1076 conn->mtu = hcon->hdev->le_mtu;
1077 else
1078 conn->mtu = hcon->hdev->acl_mtu;
1079
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 conn->src = &hcon->hdev->bdaddr;
1081 conn->dst = &hcon->dst;
1082
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001083 conn->feat_mask = 0;
1084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001086
1087 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001089 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001090 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001091 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001092 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001093
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001094 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return conn;
1097}
1098
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100
1101/* Find socket with psm and source bdaddr.
1102 * Returns closest match.
1103 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001104static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001106 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001108 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001109
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001110 list_for_each_entry(c, &chan_list, global_l) {
1111 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001112
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001113 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 continue;
1115
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001116 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001118 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001119 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001120 return c;
1121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
1123 /* Closest match */
1124 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001125 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 }
1127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001129 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001130
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001131 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132}
1133
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001134inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001136 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 struct l2cap_conn *conn;
1139 struct hci_conn *hcon;
1140 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001141 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001142 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001144 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001145 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001147 hdev = hci_get_route(dst, src);
1148 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 return -EHOSTUNREACH;
1150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001151 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001153 lock_sock(sk);
1154
1155 /* PSM must be odd and lsb of upper byte must be 0 */
1156 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1157 chan->chan_type != L2CAP_CHAN_RAW) {
1158 err = -EINVAL;
1159 goto done;
1160 }
1161
1162 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1163 err = -EINVAL;
1164 goto done;
1165 }
1166
1167 switch (chan->mode) {
1168 case L2CAP_MODE_BASIC:
1169 break;
1170 case L2CAP_MODE_ERTM:
1171 case L2CAP_MODE_STREAMING:
1172 if (!disable_ertm)
1173 break;
1174 /* fall through */
1175 default:
1176 err = -ENOTSUPP;
1177 goto done;
1178 }
1179
1180 switch (sk->sk_state) {
1181 case BT_CONNECT:
1182 case BT_CONNECT2:
1183 case BT_CONFIG:
1184 /* Already connecting */
1185 err = 0;
1186 goto done;
1187
1188 case BT_CONNECTED:
1189 /* Already connected */
1190 err = -EISCONN;
1191 goto done;
1192
1193 case BT_OPEN:
1194 case BT_BOUND:
1195 /* Can connect */
1196 break;
1197
1198 default:
1199 err = -EBADFD;
1200 goto done;
1201 }
1202
1203 /* Set destination address and psm */
1204 bacpy(&bt_sk(sk)->dst, src);
1205 chan->psm = psm;
1206 chan->dcid = cid;
1207
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001208 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001209
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001210 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001211 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001212 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001213 else
1214 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001215 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001216
Ville Tervo30e76272011-02-22 16:10:53 -03001217 if (IS_ERR(hcon)) {
1218 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001220 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
1222 conn = l2cap_conn_add(hcon, 0);
1223 if (!conn) {
1224 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001225 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 goto done;
1227 }
1228
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 /* Update source addr of the socket */
1230 bacpy(src, conn->src);
1231
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001232 l2cap_chan_add(conn, chan);
1233
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001234 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001235 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
1237 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001238 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001239 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001240 if (l2cap_chan_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001241 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001242 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001243 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 }
1245
Ville Tervo30e76272011-02-22 16:10:53 -03001246 err = 0;
1247
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001249 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 hci_dev_put(hdev);
1251 return err;
1252}
1253
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001254int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001255{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001256 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001257 DECLARE_WAITQUEUE(wait, current);
1258 int err = 0;
1259 int timeo = HZ/5;
1260
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001261 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001262 set_current_state(TASK_INTERRUPTIBLE);
1263 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001264 if (!timeo)
1265 timeo = HZ/5;
1266
1267 if (signal_pending(current)) {
1268 err = sock_intr_errno(timeo);
1269 break;
1270 }
1271
1272 release_sock(sk);
1273 timeo = schedule_timeout(timeo);
1274 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001275 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001276
1277 err = sock_error(sk);
1278 if (err)
1279 break;
1280 }
1281 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001282 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001283 return err;
1284}
1285
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001286static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001287{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001288 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1289 monitor_timer.work);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001290 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001291
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001292 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001293
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001294 lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001295 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001296 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001297 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001298 return;
1299 }
1300
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001301 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001302 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001303
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001304 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001305 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001306}
1307
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001308static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001309{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001310 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1311 retrans_timer.work);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001312 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001313
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001314 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001315
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001316 lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001317 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001318 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001319
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001320 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001321
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001322 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001323 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001324}
1325
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001326static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001327{
1328 struct sk_buff *skb;
1329
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001330 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001331 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001332 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001333 break;
1334
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001335 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001336 kfree_skb(skb);
1337
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001338 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001339 }
1340
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001341 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001342 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001343}
1344
Szymon Janc67c9e842011-07-28 16:24:33 +02001345static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001346{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001347 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001348 u32 control;
1349 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001350
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001351 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001352 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001353 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001354 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001355
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001356 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001357 fcs = crc16(0, (u8 *)skb->data,
1358 skb->len - L2CAP_FCS_SIZE);
1359 put_unaligned_le16(fcs,
1360 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001361 }
1362
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001363 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001364
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001365 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001366 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001367}
1368
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001369static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001370{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001371 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001372 u16 fcs;
1373 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001374
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001375 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001376 if (!skb)
1377 return;
1378
Szymon Jancd1726b62011-11-16 09:32:20 +01001379 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001380 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001381 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001382
Szymon Jancd1726b62011-11-16 09:32:20 +01001383 skb = skb_queue_next(&chan->tx_q, skb);
1384 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001385
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001386 if (chan->remote_max_tx &&
1387 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001388 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001389 return;
1390 }
1391
1392 tx_skb = skb_clone(skb, GFP_ATOMIC);
1393 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001394
1395 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001396 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001397
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001398 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001399 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001400
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001401 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001402 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001403
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001404 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001405
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001406 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001407 fcs = crc16(0, (u8 *)tx_skb->data,
1408 tx_skb->len - L2CAP_FCS_SIZE);
1409 put_unaligned_le16(fcs,
1410 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001411 }
1412
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001413 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001414}
1415
Szymon Janc67c9e842011-07-28 16:24:33 +02001416static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001417{
1418 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001419 u16 fcs;
1420 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001421 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001422
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001423 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001424 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001425
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001426 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001427
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001428 if (chan->remote_max_tx &&
1429 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001430 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001431 break;
1432 }
1433
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001434 tx_skb = skb_clone(skb, GFP_ATOMIC);
1435
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001436 bt_cb(skb)->retries++;
1437
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001438 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001439 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001440
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001441 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001442 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001443
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001444 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001445 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001446
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001447 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001448
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001449 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001450 fcs = crc16(0, (u8 *)skb->data,
1451 tx_skb->len - L2CAP_FCS_SIZE);
1452 put_unaligned_le16(fcs, skb->data +
1453 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001454 }
1455
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001456 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001457
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001458 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001459
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001460 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001461
1462 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001463
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301464 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001465 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301466
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001467 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001468
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001469 if (skb_queue_is_last(&chan->tx_q, skb))
1470 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001471 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001472 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001473
1474 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001475 }
1476
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001477 return nsent;
1478}
1479
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001480static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001481{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001482 int ret;
1483
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001484 if (!skb_queue_empty(&chan->tx_q))
1485 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001486
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001487 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001488 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001489 return ret;
1490}
1491
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001492static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001493{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001494 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001495
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001496 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001497
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001498 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001499 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001500 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001501 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001502 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001503 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001504
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001505 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001506 return;
1507
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001508 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001509 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001510}
1511
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001512static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001513{
1514 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001515 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001516
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001517 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001518 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001519
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001520 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001521 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001522
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001523 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001524}
1525
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001526static 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 -07001527{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001528 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001529 struct sk_buff **frag;
1530 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001532 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001533 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
1535 sent += count;
1536 len -= count;
1537
1538 /* Continuation fragments (no L2CAP header) */
1539 frag = &skb_shinfo(skb)->frag_list;
1540 while (len) {
1541 count = min_t(unsigned int, conn->mtu, len);
1542
1543 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1544 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001545 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001546 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1547 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001549 (*frag)->priority = skb->priority;
1550
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 sent += count;
1552 len -= count;
1553
1554 frag = &(*frag)->next;
1555 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
1557 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001558}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001560static struct sk_buff *l2cap_create_connless_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;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001567 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001568 struct l2cap_hdr *lh;
1569
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001570 BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001571
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));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001584 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001585
1586 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1587 if (unlikely(err < 0)) {
1588 kfree_skb(skb);
1589 return ERR_PTR(err);
1590 }
1591 return skb;
1592}
1593
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001594static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1595 struct msghdr *msg, size_t len,
1596 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001597{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001598 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001599 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001600 struct sk_buff *skb;
1601 int err, count, hlen = L2CAP_HDR_SIZE;
1602 struct l2cap_hdr *lh;
1603
1604 BT_DBG("sk %p len %d", sk, (int)len);
1605
1606 count = min_t(unsigned int, (conn->mtu - hlen), len);
1607 skb = bt_skb_send_alloc(sk, count + hlen,
1608 msg->msg_flags & MSG_DONTWAIT, &err);
1609 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001610 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001611
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001612 skb->priority = priority;
1613
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001614 /* Create L2CAP header */
1615 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001616 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001617 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1618
1619 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1620 if (unlikely(err < 0)) {
1621 kfree_skb(skb);
1622 return ERR_PTR(err);
1623 }
1624 return skb;
1625}
1626
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001627static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1628 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001629 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001630{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001631 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001632 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001633 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001634 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001635 struct l2cap_hdr *lh;
1636
1637 BT_DBG("sk %p len %d", sk, (int)len);
1638
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001639 if (!conn)
1640 return ERR_PTR(-ENOTCONN);
1641
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001642 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1643 hlen = L2CAP_EXT_HDR_SIZE;
1644 else
1645 hlen = L2CAP_ENH_HDR_SIZE;
1646
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001647 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001648 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001649
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001650 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001651 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001652
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001653 count = min_t(unsigned int, (conn->mtu - hlen), len);
1654 skb = bt_skb_send_alloc(sk, count + hlen,
1655 msg->msg_flags & MSG_DONTWAIT, &err);
1656 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001657 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001658
1659 /* Create L2CAP header */
1660 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001661 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001662 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001663
1664 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1665
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001666 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001667 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001668
1669 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1670 if (unlikely(err < 0)) {
1671 kfree_skb(skb);
1672 return ERR_PTR(err);
1673 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001674
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001675 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001676 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001677
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001678 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001679 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680}
1681
Szymon Janc67c9e842011-07-28 16:24:33 +02001682static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001683{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001684 struct sk_buff *skb;
1685 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001686 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001687 size_t size = 0;
1688
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001689 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001690 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001691 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001692 if (IS_ERR(skb))
1693 return PTR_ERR(skb);
1694
1695 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001696 len -= chan->remote_mps;
1697 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001698
1699 while (len > 0) {
1700 size_t buflen;
1701
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001702 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001703 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001704 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001705 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001706 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001707 buflen = len;
1708 }
1709
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001710 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001711 if (IS_ERR(skb)) {
1712 skb_queue_purge(&sar_queue);
1713 return PTR_ERR(skb);
1714 }
1715
1716 __skb_queue_tail(&sar_queue, skb);
1717 len -= buflen;
1718 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001719 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001720 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1721 if (chan->tx_send_head == NULL)
1722 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001723
1724 return size;
1725}
1726
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001727int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1728 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001729{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001730 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001731 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001732 int err;
1733
1734 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001735 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001736 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001737 if (IS_ERR(skb))
1738 return PTR_ERR(skb);
1739
1740 l2cap_do_send(chan, skb);
1741 return len;
1742 }
1743
1744 switch (chan->mode) {
1745 case L2CAP_MODE_BASIC:
1746 /* Check outgoing MTU */
1747 if (len > chan->omtu)
1748 return -EMSGSIZE;
1749
1750 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001751 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001752 if (IS_ERR(skb))
1753 return PTR_ERR(skb);
1754
1755 l2cap_do_send(chan, skb);
1756 err = len;
1757 break;
1758
1759 case L2CAP_MODE_ERTM:
1760 case L2CAP_MODE_STREAMING:
1761 /* Entire SDU fits into one PDU */
1762 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001763 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001764 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1765 0);
1766 if (IS_ERR(skb))
1767 return PTR_ERR(skb);
1768
1769 __skb_queue_tail(&chan->tx_q, skb);
1770
1771 if (chan->tx_send_head == NULL)
1772 chan->tx_send_head = skb;
1773
1774 } else {
1775 /* Segment SDU into multiples PDUs */
1776 err = l2cap_sar_segment_sdu(chan, msg, len);
1777 if (err < 0)
1778 return err;
1779 }
1780
1781 if (chan->mode == L2CAP_MODE_STREAMING) {
1782 l2cap_streaming_send(chan);
1783 err = len;
1784 break;
1785 }
1786
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001787 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1788 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001789 err = len;
1790 break;
1791 }
1792
1793 err = l2cap_ertm_send(chan);
1794 if (err >= 0)
1795 err = len;
1796
1797 break;
1798
1799 default:
1800 BT_DBG("bad state %1.1x", chan->mode);
1801 err = -EBADFD;
1802 }
1803
1804 return err;
1805}
1806
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807/* Copy frame to all raw sockets on that connection */
1808static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1809{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001811 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
1813 BT_DBG("conn %p", conn);
1814
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001815 rcu_read_lock();
1816
1817 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001818 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001819 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 continue;
1821
1822 /* Don't send frame to the socket it came from */
1823 if (skb->sk == sk)
1824 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001825 nskb = skb_clone(skb, GFP_ATOMIC);
1826 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001827 continue;
1828
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001829 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 kfree_skb(nskb);
1831 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001832
1833 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834}
1835
1836/* ---- L2CAP signalling commands ---- */
1837static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1838 u8 code, u8 ident, u16 dlen, void *data)
1839{
1840 struct sk_buff *skb, **frag;
1841 struct l2cap_cmd_hdr *cmd;
1842 struct l2cap_hdr *lh;
1843 int len, count;
1844
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001845 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1846 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847
1848 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1849 count = min_t(unsigned int, conn->mtu, len);
1850
1851 skb = bt_skb_alloc(count, GFP_ATOMIC);
1852 if (!skb)
1853 return NULL;
1854
1855 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001856 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001857
1858 if (conn->hcon->type == LE_LINK)
1859 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1860 else
1861 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
1863 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1864 cmd->code = code;
1865 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001866 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867
1868 if (dlen) {
1869 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1870 memcpy(skb_put(skb, count), data, count);
1871 data += count;
1872 }
1873
1874 len -= skb->len;
1875
1876 /* Continuation fragments (no L2CAP header) */
1877 frag = &skb_shinfo(skb)->frag_list;
1878 while (len) {
1879 count = min_t(unsigned int, conn->mtu, len);
1880
1881 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1882 if (!*frag)
1883 goto fail;
1884
1885 memcpy(skb_put(*frag, count), data, count);
1886
1887 len -= count;
1888 data += count;
1889
1890 frag = &(*frag)->next;
1891 }
1892
1893 return skb;
1894
1895fail:
1896 kfree_skb(skb);
1897 return NULL;
1898}
1899
1900static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1901{
1902 struct l2cap_conf_opt *opt = *ptr;
1903 int len;
1904
1905 len = L2CAP_CONF_OPT_SIZE + opt->len;
1906 *ptr += len;
1907
1908 *type = opt->type;
1909 *olen = opt->len;
1910
1911 switch (opt->len) {
1912 case 1:
1913 *val = *((u8 *) opt->val);
1914 break;
1915
1916 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001917 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 break;
1919
1920 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001921 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922 break;
1923
1924 default:
1925 *val = (unsigned long) opt->val;
1926 break;
1927 }
1928
1929 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1930 return len;
1931}
1932
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1934{
1935 struct l2cap_conf_opt *opt = *ptr;
1936
1937 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1938
1939 opt->type = type;
1940 opt->len = len;
1941
1942 switch (len) {
1943 case 1:
1944 *((u8 *) opt->val) = val;
1945 break;
1946
1947 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001948 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 break;
1950
1951 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001952 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 break;
1954
1955 default:
1956 memcpy(opt->val, (void *) val, len);
1957 break;
1958 }
1959
1960 *ptr += L2CAP_CONF_OPT_SIZE + len;
1961}
1962
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001963static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1964{
1965 struct l2cap_conf_efs efs;
1966
Szymon Janc1ec918c2011-11-16 09:32:21 +01001967 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001968 case L2CAP_MODE_ERTM:
1969 efs.id = chan->local_id;
1970 efs.stype = chan->local_stype;
1971 efs.msdu = cpu_to_le16(chan->local_msdu);
1972 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1973 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1974 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1975 break;
1976
1977 case L2CAP_MODE_STREAMING:
1978 efs.id = 1;
1979 efs.stype = L2CAP_SERV_BESTEFFORT;
1980 efs.msdu = cpu_to_le16(chan->local_msdu);
1981 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1982 efs.acc_lat = 0;
1983 efs.flush_to = 0;
1984 break;
1985
1986 default:
1987 return;
1988 }
1989
1990 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
1991 (unsigned long) &efs);
1992}
1993
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001994static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001995{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001996 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1997 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001998
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001999 lock_sock(chan->sk);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002000 l2cap_send_ack(chan);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002001 release_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002002}
2003
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002004static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002005{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002006 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002007 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002008 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002009 chan->num_acked = 0;
2010 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002011
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002012 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2013 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2014 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002015
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002016 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002017
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002018 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002019}
2020
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002021static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2022{
2023 switch (mode) {
2024 case L2CAP_MODE_STREAMING:
2025 case L2CAP_MODE_ERTM:
2026 if (l2cap_mode_supported(mode, remote_feat_mask))
2027 return mode;
2028 /* fall through */
2029 default:
2030 return L2CAP_MODE_BASIC;
2031 }
2032}
2033
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002034static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2035{
2036 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2037}
2038
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002039static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2040{
2041 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2042}
2043
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002044static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2045{
2046 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002047 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002048 /* use extended control field */
2049 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002050 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2051 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002052 chan->tx_win = min_t(u16, chan->tx_win,
2053 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002054 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2055 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002056}
2057
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002058static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002061 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002063 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002065 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002067 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002068 goto done;
2069
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002070 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002071 case L2CAP_MODE_STREAMING:
2072 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002073 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002074 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002075
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002076 if (__l2cap_efs_supported(chan))
2077 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2078
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002079 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002080 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002081 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002082 break;
2083 }
2084
2085done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002086 if (chan->imtu != L2CAP_DEFAULT_MTU)
2087 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002088
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002089 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002090 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002091 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2092 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002093 break;
2094
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002095 rfc.mode = L2CAP_MODE_BASIC;
2096 rfc.txwin_size = 0;
2097 rfc.max_transmit = 0;
2098 rfc.retrans_timeout = 0;
2099 rfc.monitor_timeout = 0;
2100 rfc.max_pdu_size = 0;
2101
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002102 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2103 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002104 break;
2105
2106 case L2CAP_MODE_ERTM:
2107 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002108 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002109 rfc.retrans_timeout = 0;
2110 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002111
2112 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2113 L2CAP_EXT_HDR_SIZE -
2114 L2CAP_SDULEN_SIZE -
2115 L2CAP_FCS_SIZE);
2116 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002117
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002118 l2cap_txwin_setup(chan);
2119
2120 rfc.txwin_size = min_t(u16, chan->tx_win,
2121 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002122
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002123 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2124 (unsigned long) &rfc);
2125
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002126 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2127 l2cap_add_opt_efs(&ptr, chan);
2128
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002129 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002130 break;
2131
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002132 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002133 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002134 chan->fcs = L2CAP_FCS_NONE;
2135 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002136 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002137
2138 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2139 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2140 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002141 break;
2142
2143 case L2CAP_MODE_STREAMING:
2144 rfc.mode = L2CAP_MODE_STREAMING;
2145 rfc.txwin_size = 0;
2146 rfc.max_transmit = 0;
2147 rfc.retrans_timeout = 0;
2148 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002149
2150 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2151 L2CAP_EXT_HDR_SIZE -
2152 L2CAP_SDULEN_SIZE -
2153 L2CAP_FCS_SIZE);
2154 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002155
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002156 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2157 (unsigned long) &rfc);
2158
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002159 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2160 l2cap_add_opt_efs(&ptr, chan);
2161
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002162 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002163 break;
2164
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002165 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002166 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002167 chan->fcs = L2CAP_FCS_NONE;
2168 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002169 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002170 break;
2171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002173 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002174 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
2176 return ptr - data;
2177}
2178
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002179static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002181 struct l2cap_conf_rsp *rsp = data;
2182 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002183 void *req = chan->conf_req;
2184 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002185 int type, hint, olen;
2186 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002187 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002188 struct l2cap_conf_efs efs;
2189 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002190 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002191 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002192 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002194 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002195
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002196 while (len >= L2CAP_CONF_OPT_SIZE) {
2197 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002199 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002200 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002201
2202 switch (type) {
2203 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002204 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002205 break;
2206
2207 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002208 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002209 break;
2210
2211 case L2CAP_CONF_QOS:
2212 break;
2213
Marcel Holtmann6464f352007-10-20 13:39:51 +02002214 case L2CAP_CONF_RFC:
2215 if (olen == sizeof(rfc))
2216 memcpy(&rfc, (void *) val, olen);
2217 break;
2218
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002219 case L2CAP_CONF_FCS:
2220 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002221 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002222 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002223
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002224 case L2CAP_CONF_EFS:
2225 remote_efs = 1;
2226 if (olen == sizeof(efs))
2227 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002228 break;
2229
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002230 case L2CAP_CONF_EWS:
2231 if (!enable_hs)
2232 return -ECONNREFUSED;
2233
2234 set_bit(FLAG_EXT_CTRL, &chan->flags);
2235 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002236 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002237 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002238 break;
2239
2240 default:
2241 if (hint)
2242 break;
2243
2244 result = L2CAP_CONF_UNKNOWN;
2245 *((u8 *) ptr++) = type;
2246 break;
2247 }
2248 }
2249
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002250 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002251 goto done;
2252
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002253 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002254 case L2CAP_MODE_STREAMING:
2255 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002256 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002257 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002258 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002259 break;
2260 }
2261
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002262 if (remote_efs) {
2263 if (__l2cap_efs_supported(chan))
2264 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2265 else
2266 return -ECONNREFUSED;
2267 }
2268
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002269 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002270 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002271
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002272 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002273 }
2274
2275done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002276 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002277 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002278 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002279
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002280 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002281 return -ECONNREFUSED;
2282
2283 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2284 sizeof(rfc), (unsigned long) &rfc);
2285 }
2286
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002287 if (result == L2CAP_CONF_SUCCESS) {
2288 /* Configure output options and let the other side know
2289 * which ones we don't like. */
2290
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002291 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2292 result = L2CAP_CONF_UNACCEPT;
2293 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002294 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002295 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002296 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002297 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002298
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002299 if (remote_efs) {
2300 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2301 efs.stype != L2CAP_SERV_NOTRAFIC &&
2302 efs.stype != chan->local_stype) {
2303
2304 result = L2CAP_CONF_UNACCEPT;
2305
2306 if (chan->num_conf_req >= 1)
2307 return -ECONNREFUSED;
2308
2309 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002310 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002311 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002312 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002313 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002314 result = L2CAP_CONF_PENDING;
2315 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002316 }
2317 }
2318
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002319 switch (rfc.mode) {
2320 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002321 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002322 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002323 break;
2324
2325 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002326 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2327 chan->remote_tx_win = rfc.txwin_size;
2328 else
2329 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2330
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002331 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002332
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002333 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2334 chan->conn->mtu -
2335 L2CAP_EXT_HDR_SIZE -
2336 L2CAP_SDULEN_SIZE -
2337 L2CAP_FCS_SIZE);
2338 rfc.max_pdu_size = cpu_to_le16(size);
2339 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002340
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002341 rfc.retrans_timeout =
2342 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2343 rfc.monitor_timeout =
2344 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002345
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002346 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002347
2348 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2349 sizeof(rfc), (unsigned long) &rfc);
2350
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002351 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2352 chan->remote_id = efs.id;
2353 chan->remote_stype = efs.stype;
2354 chan->remote_msdu = le16_to_cpu(efs.msdu);
2355 chan->remote_flush_to =
2356 le32_to_cpu(efs.flush_to);
2357 chan->remote_acc_lat =
2358 le32_to_cpu(efs.acc_lat);
2359 chan->remote_sdu_itime =
2360 le32_to_cpu(efs.sdu_itime);
2361 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2362 sizeof(efs), (unsigned long) &efs);
2363 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002364 break;
2365
2366 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002367 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2368 chan->conn->mtu -
2369 L2CAP_EXT_HDR_SIZE -
2370 L2CAP_SDULEN_SIZE -
2371 L2CAP_FCS_SIZE);
2372 rfc.max_pdu_size = cpu_to_le16(size);
2373 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002374
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002375 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002376
2377 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2378 sizeof(rfc), (unsigned long) &rfc);
2379
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002380 break;
2381
2382 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002383 result = L2CAP_CONF_UNACCEPT;
2384
2385 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002386 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002387 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002388
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002389 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002390 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002391 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002392 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002393 rsp->result = cpu_to_le16(result);
2394 rsp->flags = cpu_to_le16(0x0000);
2395
2396 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397}
2398
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002399static 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 -03002400{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002401 struct l2cap_conf_req *req = data;
2402 void *ptr = req->data;
2403 int type, olen;
2404 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002405 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002406 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002407
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002408 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002409
2410 while (len >= L2CAP_CONF_OPT_SIZE) {
2411 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2412
2413 switch (type) {
2414 case L2CAP_CONF_MTU:
2415 if (val < L2CAP_DEFAULT_MIN_MTU) {
2416 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002417 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002418 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002419 chan->imtu = val;
2420 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002421 break;
2422
2423 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002424 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002425 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002426 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002427 break;
2428
2429 case L2CAP_CONF_RFC:
2430 if (olen == sizeof(rfc))
2431 memcpy(&rfc, (void *)val, olen);
2432
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002433 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002434 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002435 return -ECONNREFUSED;
2436
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002437 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002438
2439 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2440 sizeof(rfc), (unsigned long) &rfc);
2441 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002442
2443 case L2CAP_CONF_EWS:
2444 chan->tx_win = min_t(u16, val,
2445 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002446 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2447 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002448 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002449
2450 case L2CAP_CONF_EFS:
2451 if (olen == sizeof(efs))
2452 memcpy(&efs, (void *)val, olen);
2453
2454 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2455 efs.stype != L2CAP_SERV_NOTRAFIC &&
2456 efs.stype != chan->local_stype)
2457 return -ECONNREFUSED;
2458
2459 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2460 sizeof(efs), (unsigned long) &efs);
2461 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002462 }
2463 }
2464
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002465 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002466 return -ECONNREFUSED;
2467
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002468 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002469
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002470 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002471 switch (rfc.mode) {
2472 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002473 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2474 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2475 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002476
2477 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2478 chan->local_msdu = le16_to_cpu(efs.msdu);
2479 chan->local_sdu_itime =
2480 le32_to_cpu(efs.sdu_itime);
2481 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2482 chan->local_flush_to =
2483 le32_to_cpu(efs.flush_to);
2484 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002485 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002486
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002487 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002488 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002489 }
2490 }
2491
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002492 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002493 req->flags = cpu_to_le16(0x0000);
2494
2495 return ptr - data;
2496}
2497
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002498static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499{
2500 struct l2cap_conf_rsp *rsp = data;
2501 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002503 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002505 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002506 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002507 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508
2509 return ptr - data;
2510}
2511
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002512void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002513{
2514 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002515 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002516 u8 buf[128];
2517
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002518 rsp.scid = cpu_to_le16(chan->dcid);
2519 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002520 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2521 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2522 l2cap_send_cmd(conn, chan->ident,
2523 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2524
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002525 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002526 return;
2527
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002528 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2529 l2cap_build_conf_req(chan, buf), buf);
2530 chan->num_conf_req++;
2531}
2532
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002533static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002534{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002535 int type, olen;
2536 unsigned long val;
2537 struct l2cap_conf_rfc rfc;
2538
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002539 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002540
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002541 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002542 return;
2543
2544 while (len >= L2CAP_CONF_OPT_SIZE) {
2545 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2546
2547 switch (type) {
2548 case L2CAP_CONF_RFC:
2549 if (olen == sizeof(rfc))
2550 memcpy(&rfc, (void *)val, olen);
2551 goto done;
2552 }
2553 }
2554
Mat Martineau36e999a2011-12-08 17:23:21 -08002555 /* Use sane default values in case a misbehaving remote device
2556 * did not send an RFC option.
2557 */
2558 rfc.mode = chan->mode;
2559 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2560 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2561 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2562
2563 BT_ERR("Expected RFC option was not found, using defaults");
2564
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002565done:
2566 switch (rfc.mode) {
2567 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002568 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2569 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2570 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002571 break;
2572 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002573 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002574 }
2575}
2576
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002577static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2578{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002579 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002580
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002581 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002582 return 0;
2583
2584 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2585 cmd->ident == conn->info_ident) {
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02002586 cancel_delayed_work_sync(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002587
2588 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002589 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002590
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002591 l2cap_conn_start(conn);
2592 }
2593
2594 return 0;
2595}
2596
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2598{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2600 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002601 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002602 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002603 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604
2605 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002606 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2609
2610 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002611 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2612 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 result = L2CAP_CR_BAD_PSM;
2614 goto sendresp;
2615 }
2616
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002617 parent = pchan->sk;
2618
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002619 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002620
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002621 /* Check if the ACL is secure enough (if not SDP) */
2622 if (psm != cpu_to_le16(0x0001) &&
2623 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002624 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002625 result = L2CAP_CR_SEC_BLOCK;
2626 goto response;
2627 }
2628
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 result = L2CAP_CR_NO_MEM;
2630
2631 /* Check for backlog size */
2632 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002633 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 goto response;
2635 }
2636
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002637 chan = pchan->ops->new_connection(pchan->data);
2638 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 goto response;
2640
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002641 sk = chan->sk;
2642
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002644 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002646 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 goto response;
2648 }
2649
2650 hci_conn_hold(conn->hcon);
2651
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 bacpy(&bt_sk(sk)->src, conn->src);
2653 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002654 chan->psm = psm;
2655 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002657 bt_accept_enqueue(parent, sk);
2658
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02002659 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002660
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002661 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002663 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002665 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
Marcel Holtmann984947d2009-02-06 23:35:19 +01002667 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002668 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002669 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002670 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002671 result = L2CAP_CR_PEND;
2672 status = L2CAP_CS_AUTHOR_PEND;
2673 parent->sk_data_ready(parent, 0);
2674 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002675 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002676 result = L2CAP_CR_SUCCESS;
2677 status = L2CAP_CS_NO_INFO;
2678 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002679 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002680 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002681 result = L2CAP_CR_PEND;
2682 status = L2CAP_CS_AUTHEN_PEND;
2683 }
2684 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002685 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002686 result = L2CAP_CR_PEND;
2687 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 }
2689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002691 release_sock(parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
2693sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002694 rsp.scid = cpu_to_le16(scid);
2695 rsp.dcid = cpu_to_le16(dcid);
2696 rsp.result = cpu_to_le16(result);
2697 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002699
2700 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2701 struct l2cap_info_req info;
2702 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2703
2704 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2705 conn->info_ident = l2cap_get_ident(conn);
2706
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02002707 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002708 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2709
2710 l2cap_send_cmd(conn, conn->info_ident,
2711 L2CAP_INFO_REQ, sizeof(info), &info);
2712 }
2713
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002714 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002715 result == L2CAP_CR_SUCCESS) {
2716 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002717 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002718 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002719 l2cap_build_conf_req(chan, buf), buf);
2720 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002721 }
2722
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 return 0;
2724}
2725
2726static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2727{
2728 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2729 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002730 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 struct sock *sk;
2732 u8 req[128];
2733
2734 scid = __le16_to_cpu(rsp->scid);
2735 dcid = __le16_to_cpu(rsp->dcid);
2736 result = __le16_to_cpu(rsp->result);
2737 status = __le16_to_cpu(rsp->status);
2738
2739 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2740
2741 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002742 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002743 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002744 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002746 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002747 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002748 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 }
2750
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002751 sk = chan->sk;
2752
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 switch (result) {
2754 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002755 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002756 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002757 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002758 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002759
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002760 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002761 break;
2762
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002764 l2cap_build_conf_req(chan, req), req);
2765 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 break;
2767
2768 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002769 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 break;
2771
2772 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002773 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 break;
2775 }
2776
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002777 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 return 0;
2779}
2780
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002781static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002782{
2783 /* FCS is enabled only in ERTM or streaming mode, if one or both
2784 * sides request it.
2785 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002786 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002787 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002788 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002789 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002790}
2791
Al Viro88219a02007-07-29 00:17:25 -07002792static 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 -07002793{
2794 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2795 u16 dcid, flags;
2796 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002797 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002799 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
2801 dcid = __le16_to_cpu(req->dcid);
2802 flags = __le16_to_cpu(req->flags);
2803
2804 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2805
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002806 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002807 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 return -ENOENT;
2809
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002810 sk = chan->sk;
2811
David S. Miller033b1142011-07-21 13:38:42 -07002812 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002813 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002814
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002815 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2816 rej.scid = cpu_to_le16(chan->scid);
2817 rej.dcid = cpu_to_le16(chan->dcid);
2818
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002819 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2820 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002821 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002822 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002823
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002824 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002825 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002826 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002827 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002828 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002829 L2CAP_CONF_REJECT, flags), rsp);
2830 goto unlock;
2831 }
2832
2833 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002834 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2835 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836
2837 if (flags & 0x0001) {
2838 /* Incomplete config. Send empty response. */
2839 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002840 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002841 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 goto unlock;
2843 }
2844
2845 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002846 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002847 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002848 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002852 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002853 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002854
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002855 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002856 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002857
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002858 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002859 goto unlock;
2860
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002861 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002862 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002863
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002864 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002865
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002866 chan->next_tx_seq = 0;
2867 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002868 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002869 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002870 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002871
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002873 goto unlock;
2874 }
2875
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002876 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002877 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002879 l2cap_build_conf_req(chan, buf), buf);
2880 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 }
2882
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002883 /* Got Conf Rsp PENDING from remote side and asume we sent
2884 Conf Rsp PENDING in the code above */
2885 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2886 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2887
2888 /* check compatibility */
2889
2890 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2891 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2892
2893 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002894 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002895 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2896 }
2897
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898unlock:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002899 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 return 0;
2901}
2902
2903static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2904{
2905 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2906 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002907 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002909 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
2911 scid = __le16_to_cpu(rsp->scid);
2912 flags = __le16_to_cpu(rsp->flags);
2913 result = __le16_to_cpu(rsp->result);
2914
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002915 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2916 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002918 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002919 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 return 0;
2921
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002922 sk = chan->sk;
2923
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 switch (result) {
2925 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002926 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002927 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 break;
2929
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002930 case L2CAP_CONF_PENDING:
2931 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2932
2933 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2934 char buf[64];
2935
2936 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2937 buf, &result);
2938 if (len < 0) {
2939 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2940 goto done;
2941 }
2942
2943 /* check compatibility */
2944
2945 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2946 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2947
2948 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002949 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002950 L2CAP_CONF_SUCCESS, 0x0000), buf);
2951 }
2952 goto done;
2953
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002955 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002956 char req[64];
2957
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002958 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002959 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002960 goto done;
2961 }
2962
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002963 /* throw out any old stored conf requests */
2964 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002965 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2966 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002967 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002968 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002969 goto done;
2970 }
2971
2972 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2973 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002974 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002975 if (result != L2CAP_CONF_SUCCESS)
2976 goto done;
2977 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 }
2979
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002980 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002981 sk->sk_err = ECONNRESET;
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002982 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002983 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 goto done;
2985 }
2986
2987 if (flags & 0x01)
2988 goto done;
2989
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002990 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002992 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002993 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002994
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002995 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002996 chan->next_tx_seq = 0;
2997 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002998 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002999 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003000 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003001
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 l2cap_chan_ready(sk);
3003 }
3004
3005done:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003006 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 return 0;
3008}
3009
3010static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3011{
3012 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3013 struct l2cap_disconn_rsp rsp;
3014 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003015 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 struct sock *sk;
3017
3018 scid = __le16_to_cpu(req->scid);
3019 dcid = __le16_to_cpu(req->dcid);
3020
3021 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3022
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003023 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003024 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 return 0;
3026
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003027 sk = chan->sk;
3028
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003029 rsp.dcid = cpu_to_le16(chan->scid);
3030 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3032
3033 sk->sk_shutdown = SHUTDOWN_MASK;
3034
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003035 l2cap_chan_del(chan, ECONNRESET);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003036 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003038 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 return 0;
3040}
3041
3042static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3043{
3044 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3045 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003046 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 struct sock *sk;
3048
3049 scid = __le16_to_cpu(rsp->scid);
3050 dcid = __le16_to_cpu(rsp->dcid);
3051
3052 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3053
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003054 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003055 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 return 0;
3057
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003058 sk = chan->sk;
3059
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003060 l2cap_chan_del(chan, 0);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003061 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003063 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 return 0;
3065}
3066
3067static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3068{
3069 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 u16 type;
3071
3072 type = __le16_to_cpu(req->type);
3073
3074 BT_DBG("type 0x%4.4x", type);
3075
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003076 if (type == L2CAP_IT_FEAT_MASK) {
3077 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003078 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003079 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3080 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3081 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003082 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003083 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3084 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003085 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003086 feat_mask |= L2CAP_FEAT_EXT_FLOW
3087 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003088
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003089 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003090 l2cap_send_cmd(conn, cmd->ident,
3091 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003092 } else if (type == L2CAP_IT_FIXED_CHAN) {
3093 u8 buf[12];
3094 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003095
3096 if (enable_hs)
3097 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3098 else
3099 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3100
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003101 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3102 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003103 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003104 l2cap_send_cmd(conn, cmd->ident,
3105 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003106 } else {
3107 struct l2cap_info_rsp rsp;
3108 rsp.type = cpu_to_le16(type);
3109 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3110 l2cap_send_cmd(conn, cmd->ident,
3111 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113
3114 return 0;
3115}
3116
3117static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3118{
3119 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3120 u16 type, result;
3121
3122 type = __le16_to_cpu(rsp->type);
3123 result = __le16_to_cpu(rsp->result);
3124
3125 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3126
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003127 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3128 if (cmd->ident != conn->info_ident ||
3129 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3130 return 0;
3131
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02003132 cancel_delayed_work_sync(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003133
Ville Tervoadb08ed2010-08-04 09:43:33 +03003134 if (result != L2CAP_IR_SUCCESS) {
3135 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3136 conn->info_ident = 0;
3137
3138 l2cap_conn_start(conn);
3139
3140 return 0;
3141 }
3142
Marcel Holtmann984947d2009-02-06 23:35:19 +01003143 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003144 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003145
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003146 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003147 struct l2cap_info_req req;
3148 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3149
3150 conn->info_ident = l2cap_get_ident(conn);
3151
3152 l2cap_send_cmd(conn, conn->info_ident,
3153 L2CAP_INFO_REQ, sizeof(req), &req);
3154 } else {
3155 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3156 conn->info_ident = 0;
3157
3158 l2cap_conn_start(conn);
3159 }
3160 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003161 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003162 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003163
3164 l2cap_conn_start(conn);
3165 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003166
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 return 0;
3168}
3169
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003170static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3171 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3172 void *data)
3173{
3174 struct l2cap_create_chan_req *req = data;
3175 struct l2cap_create_chan_rsp rsp;
3176 u16 psm, scid;
3177
3178 if (cmd_len != sizeof(*req))
3179 return -EPROTO;
3180
3181 if (!enable_hs)
3182 return -EINVAL;
3183
3184 psm = le16_to_cpu(req->psm);
3185 scid = le16_to_cpu(req->scid);
3186
3187 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3188
3189 /* Placeholder: Always reject */
3190 rsp.dcid = 0;
3191 rsp.scid = cpu_to_le16(scid);
3192 rsp.result = L2CAP_CR_NO_MEM;
3193 rsp.status = L2CAP_CS_NO_INFO;
3194
3195 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3196 sizeof(rsp), &rsp);
3197
3198 return 0;
3199}
3200
3201static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3202 struct l2cap_cmd_hdr *cmd, void *data)
3203{
3204 BT_DBG("conn %p", conn);
3205
3206 return l2cap_connect_rsp(conn, cmd, data);
3207}
3208
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003209static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3210 u16 icid, u16 result)
3211{
3212 struct l2cap_move_chan_rsp rsp;
3213
3214 BT_DBG("icid %d, result %d", icid, result);
3215
3216 rsp.icid = cpu_to_le16(icid);
3217 rsp.result = cpu_to_le16(result);
3218
3219 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3220}
3221
3222static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3223 struct l2cap_chan *chan, u16 icid, u16 result)
3224{
3225 struct l2cap_move_chan_cfm cfm;
3226 u8 ident;
3227
3228 BT_DBG("icid %d, result %d", icid, result);
3229
3230 ident = l2cap_get_ident(conn);
3231 if (chan)
3232 chan->ident = ident;
3233
3234 cfm.icid = cpu_to_le16(icid);
3235 cfm.result = cpu_to_le16(result);
3236
3237 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3238}
3239
3240static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3241 u16 icid)
3242{
3243 struct l2cap_move_chan_cfm_rsp rsp;
3244
3245 BT_DBG("icid %d", icid);
3246
3247 rsp.icid = cpu_to_le16(icid);
3248 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3249}
3250
3251static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3252 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3253{
3254 struct l2cap_move_chan_req *req = data;
3255 u16 icid = 0;
3256 u16 result = L2CAP_MR_NOT_ALLOWED;
3257
3258 if (cmd_len != sizeof(*req))
3259 return -EPROTO;
3260
3261 icid = le16_to_cpu(req->icid);
3262
3263 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3264
3265 if (!enable_hs)
3266 return -EINVAL;
3267
3268 /* Placeholder: Always refuse */
3269 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3270
3271 return 0;
3272}
3273
3274static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3275 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3276{
3277 struct l2cap_move_chan_rsp *rsp = data;
3278 u16 icid, result;
3279
3280 if (cmd_len != sizeof(*rsp))
3281 return -EPROTO;
3282
3283 icid = le16_to_cpu(rsp->icid);
3284 result = le16_to_cpu(rsp->result);
3285
3286 BT_DBG("icid %d, result %d", icid, result);
3287
3288 /* Placeholder: Always unconfirmed */
3289 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3290
3291 return 0;
3292}
3293
3294static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3295 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3296{
3297 struct l2cap_move_chan_cfm *cfm = data;
3298 u16 icid, result;
3299
3300 if (cmd_len != sizeof(*cfm))
3301 return -EPROTO;
3302
3303 icid = le16_to_cpu(cfm->icid);
3304 result = le16_to_cpu(cfm->result);
3305
3306 BT_DBG("icid %d, result %d", icid, result);
3307
3308 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3309
3310 return 0;
3311}
3312
3313static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3314 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3315{
3316 struct l2cap_move_chan_cfm_rsp *rsp = data;
3317 u16 icid;
3318
3319 if (cmd_len != sizeof(*rsp))
3320 return -EPROTO;
3321
3322 icid = le16_to_cpu(rsp->icid);
3323
3324 BT_DBG("icid %d", icid);
3325
3326 return 0;
3327}
3328
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003329static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003330 u16 to_multiplier)
3331{
3332 u16 max_latency;
3333
3334 if (min > max || min < 6 || max > 3200)
3335 return -EINVAL;
3336
3337 if (to_multiplier < 10 || to_multiplier > 3200)
3338 return -EINVAL;
3339
3340 if (max >= to_multiplier * 8)
3341 return -EINVAL;
3342
3343 max_latency = (to_multiplier * 8 / max) - 1;
3344 if (latency > 499 || latency > max_latency)
3345 return -EINVAL;
3346
3347 return 0;
3348}
3349
3350static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3351 struct l2cap_cmd_hdr *cmd, u8 *data)
3352{
3353 struct hci_conn *hcon = conn->hcon;
3354 struct l2cap_conn_param_update_req *req;
3355 struct l2cap_conn_param_update_rsp rsp;
3356 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003357 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003358
3359 if (!(hcon->link_mode & HCI_LM_MASTER))
3360 return -EINVAL;
3361
3362 cmd_len = __le16_to_cpu(cmd->len);
3363 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3364 return -EPROTO;
3365
3366 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003367 min = __le16_to_cpu(req->min);
3368 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003369 latency = __le16_to_cpu(req->latency);
3370 to_multiplier = __le16_to_cpu(req->to_multiplier);
3371
3372 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3373 min, max, latency, to_multiplier);
3374
3375 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003376
3377 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3378 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003379 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3380 else
3381 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3382
3383 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3384 sizeof(rsp), &rsp);
3385
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003386 if (!err)
3387 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3388
Claudio Takahaside731152011-02-11 19:28:55 -02003389 return 0;
3390}
3391
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003392static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3393 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3394{
3395 int err = 0;
3396
3397 switch (cmd->code) {
3398 case L2CAP_COMMAND_REJ:
3399 l2cap_command_rej(conn, cmd, data);
3400 break;
3401
3402 case L2CAP_CONN_REQ:
3403 err = l2cap_connect_req(conn, cmd, data);
3404 break;
3405
3406 case L2CAP_CONN_RSP:
3407 err = l2cap_connect_rsp(conn, cmd, data);
3408 break;
3409
3410 case L2CAP_CONF_REQ:
3411 err = l2cap_config_req(conn, cmd, cmd_len, data);
3412 break;
3413
3414 case L2CAP_CONF_RSP:
3415 err = l2cap_config_rsp(conn, cmd, data);
3416 break;
3417
3418 case L2CAP_DISCONN_REQ:
3419 err = l2cap_disconnect_req(conn, cmd, data);
3420 break;
3421
3422 case L2CAP_DISCONN_RSP:
3423 err = l2cap_disconnect_rsp(conn, cmd, data);
3424 break;
3425
3426 case L2CAP_ECHO_REQ:
3427 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3428 break;
3429
3430 case L2CAP_ECHO_RSP:
3431 break;
3432
3433 case L2CAP_INFO_REQ:
3434 err = l2cap_information_req(conn, cmd, data);
3435 break;
3436
3437 case L2CAP_INFO_RSP:
3438 err = l2cap_information_rsp(conn, cmd, data);
3439 break;
3440
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003441 case L2CAP_CREATE_CHAN_REQ:
3442 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3443 break;
3444
3445 case L2CAP_CREATE_CHAN_RSP:
3446 err = l2cap_create_channel_rsp(conn, cmd, data);
3447 break;
3448
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003449 case L2CAP_MOVE_CHAN_REQ:
3450 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3451 break;
3452
3453 case L2CAP_MOVE_CHAN_RSP:
3454 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3455 break;
3456
3457 case L2CAP_MOVE_CHAN_CFM:
3458 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3459 break;
3460
3461 case L2CAP_MOVE_CHAN_CFM_RSP:
3462 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3463 break;
3464
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003465 default:
3466 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3467 err = -EINVAL;
3468 break;
3469 }
3470
3471 return err;
3472}
3473
3474static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3475 struct l2cap_cmd_hdr *cmd, u8 *data)
3476{
3477 switch (cmd->code) {
3478 case L2CAP_COMMAND_REJ:
3479 return 0;
3480
3481 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003482 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003483
3484 case L2CAP_CONN_PARAM_UPDATE_RSP:
3485 return 0;
3486
3487 default:
3488 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3489 return -EINVAL;
3490 }
3491}
3492
3493static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3494 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495{
3496 u8 *data = skb->data;
3497 int len = skb->len;
3498 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003499 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500
3501 l2cap_raw_recv(conn, skb);
3502
3503 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003504 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3506 data += L2CAP_CMD_HDR_SIZE;
3507 len -= L2CAP_CMD_HDR_SIZE;
3508
Al Viro88219a02007-07-29 00:17:25 -07003509 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510
Al Viro88219a02007-07-29 00:17:25 -07003511 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 -07003512
Al Viro88219a02007-07-29 00:17:25 -07003513 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 BT_DBG("corrupted command");
3515 break;
3516 }
3517
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003518 if (conn->hcon->type == LE_LINK)
3519 err = l2cap_le_sig_cmd(conn, &cmd, data);
3520 else
3521 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522
3523 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003524 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003525
3526 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527
3528 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003529 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3531 }
3532
Al Viro88219a02007-07-29 00:17:25 -07003533 data += cmd_len;
3534 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 }
3536
3537 kfree_skb(skb);
3538}
3539
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003540static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003541{
3542 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003543 int hdr_size;
3544
3545 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3546 hdr_size = L2CAP_EXT_HDR_SIZE;
3547 else
3548 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003549
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003550 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003551 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003552 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3553 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3554
3555 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003556 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003557 }
3558 return 0;
3559}
3560
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003561static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003562{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003563 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003564
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003565 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003566
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003567 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003568
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003569 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003570 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003571 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003572 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003573 }
3574
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003575 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003576 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003577
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003578 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003579
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003580 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003581 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003582 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003583 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003584 }
3585}
3586
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003587static 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 -03003588{
3589 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003590 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003591
3592 bt_cb(skb)->tx_seq = tx_seq;
3593 bt_cb(skb)->sar = sar;
3594
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003595 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003596
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003597 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003598
Szymon Janc039d9572011-11-16 09:32:19 +01003599 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003600 if (bt_cb(next_skb)->tx_seq == tx_seq)
3601 return -EINVAL;
3602
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003603 next_tx_seq_offset = __seq_offset(chan,
3604 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003605
3606 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003607 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003608 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003609 }
3610
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003611 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003612 next_skb = NULL;
3613 else
3614 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3615 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003616
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003617 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003618
3619 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003620}
3621
Mat Martineau84084a32011-07-22 14:54:00 -07003622static void append_skb_frag(struct sk_buff *skb,
3623 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003624{
Mat Martineau84084a32011-07-22 14:54:00 -07003625 /* skb->len reflects data in skb as well as all fragments
3626 * skb->data_len reflects only data in fragments
3627 */
3628 if (!skb_has_frag_list(skb))
3629 skb_shinfo(skb)->frag_list = new_frag;
3630
3631 new_frag->next = NULL;
3632
3633 (*last_frag)->next = new_frag;
3634 *last_frag = new_frag;
3635
3636 skb->len += new_frag->len;
3637 skb->data_len += new_frag->len;
3638 skb->truesize += new_frag->truesize;
3639}
3640
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003641static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003642{
3643 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003644
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003645 switch (__get_ctrl_sar(chan, control)) {
3646 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003647 if (chan->sdu)
3648 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003649
Mat Martineau84084a32011-07-22 14:54:00 -07003650 err = chan->ops->recv(chan->data, skb);
3651 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003652
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003653 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003654 if (chan->sdu)
3655 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003656
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003657 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003658 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003659
Mat Martineau84084a32011-07-22 14:54:00 -07003660 if (chan->sdu_len > chan->imtu) {
3661 err = -EMSGSIZE;
3662 break;
3663 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003664
Mat Martineau84084a32011-07-22 14:54:00 -07003665 if (skb->len >= chan->sdu_len)
3666 break;
3667
3668 chan->sdu = skb;
3669 chan->sdu_last_frag = skb;
3670
3671 skb = NULL;
3672 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003673 break;
3674
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003675 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003676 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003677 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003678
Mat Martineau84084a32011-07-22 14:54:00 -07003679 append_skb_frag(chan->sdu, skb,
3680 &chan->sdu_last_frag);
3681 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003682
Mat Martineau84084a32011-07-22 14:54:00 -07003683 if (chan->sdu->len >= chan->sdu_len)
3684 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003685
Mat Martineau84084a32011-07-22 14:54:00 -07003686 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003687 break;
3688
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003689 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003690 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003691 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003692
Mat Martineau84084a32011-07-22 14:54:00 -07003693 append_skb_frag(chan->sdu, skb,
3694 &chan->sdu_last_frag);
3695 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003696
Mat Martineau84084a32011-07-22 14:54:00 -07003697 if (chan->sdu->len != chan->sdu_len)
3698 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003699
Mat Martineau84084a32011-07-22 14:54:00 -07003700 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003701
Mat Martineau84084a32011-07-22 14:54:00 -07003702 if (!err) {
3703 /* Reassembly complete */
3704 chan->sdu = NULL;
3705 chan->sdu_last_frag = NULL;
3706 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003707 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003708 break;
3709 }
3710
Mat Martineau84084a32011-07-22 14:54:00 -07003711 if (err) {
3712 kfree_skb(skb);
3713 kfree_skb(chan->sdu);
3714 chan->sdu = NULL;
3715 chan->sdu_last_frag = NULL;
3716 chan->sdu_len = 0;
3717 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003718
Mat Martineau84084a32011-07-22 14:54:00 -07003719 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003720}
3721
Mat Martineau26f880d2011-07-07 09:39:01 -07003722static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003723{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003724 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003725
Mat Martineau26f880d2011-07-07 09:39:01 -07003726 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003727
Mat Martineau26f880d2011-07-07 09:39:01 -07003728 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3729
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003730 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003731 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Mat Martineau26f880d2011-07-07 09:39:01 -07003732 l2cap_send_sframe(chan, control);
3733
3734 set_bit(CONN_RNR_SENT, &chan->conn_state);
3735
3736 __clear_ack_timer(chan);
3737}
3738
3739static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3740{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003741 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003742
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003743 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003744 goto done;
3745
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003746 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003747 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003748 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003749 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003750 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003751
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003752 __clear_retrans_timer(chan);
3753 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003754
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003755 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003756
3757done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003758 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3759 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003760
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003761 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003762}
3763
Mat Martineaue3281402011-07-07 09:39:02 -07003764void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003765{
Mat Martineaue3281402011-07-07 09:39:02 -07003766 if (chan->mode == L2CAP_MODE_ERTM) {
3767 if (busy)
3768 l2cap_ertm_enter_local_busy(chan);
3769 else
3770 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003771 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003772}
3773
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003774static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003775{
3776 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003777 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003778
Mat Martineaue3281402011-07-07 09:39:02 -07003779 while ((skb = skb_peek(&chan->srej_q)) &&
3780 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3781 int err;
3782
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003783 if (bt_cb(skb)->tx_seq != tx_seq)
3784 break;
3785
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003786 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003787 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003788 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003789
3790 if (err < 0) {
3791 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3792 break;
3793 }
3794
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003795 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3796 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003797 }
3798}
3799
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003800static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003801{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003802 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003803 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003804
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003805 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003806 if (l->tx_seq == tx_seq) {
3807 list_del(&l->list);
3808 kfree(l);
3809 return;
3810 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003811 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003812 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003813 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003814 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003815 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003816 }
3817}
3818
Szymon Jancaef89f22011-11-16 09:32:18 +01003819static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003820{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003821 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003822 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003823
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003824 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003825 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003826 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003827 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003828
3829 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003830 if (!new)
3831 return -ENOMEM;
3832
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003833 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003834
3835 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3836
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003837 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003838 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003839
3840 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003841
3842 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003843}
3844
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003845static 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 -03003846{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003847 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003848 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003849 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003850 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003851 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003852 int err = 0;
3853
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003854 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 -03003855 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003856
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003857 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003858 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003859 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003860 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003861 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003862 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003863 }
3864
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003865 chan->expected_ack_seq = req_seq;
3866 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003867
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003868 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003869
3870 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003871 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003872 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003873 goto drop;
3874 }
3875
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003876 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003877 goto drop;
3878
Mat Martineau02f1b642011-06-29 14:35:19 -07003879 if (tx_seq == chan->expected_tx_seq)
3880 goto expected;
3881
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003882 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003883 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003884
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003885 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003886 struct srej_list, list);
3887 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003888 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003889 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003890
3891 list_del(&first->list);
3892 kfree(first);
3893
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003894 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003895 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003896 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003897 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003898 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003899 }
3900 } else {
3901 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003902
3903 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003904 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003905 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003906
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003907 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003908 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003909 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003910 return 0;
3911 }
3912 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003913
3914 err = l2cap_send_srejframe(chan, tx_seq);
3915 if (err < 0) {
3916 l2cap_send_disconn_req(chan->conn, chan, -err);
3917 return err;
3918 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003919 }
3920 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003921 expected_tx_seq_offset = __seq_offset(chan,
3922 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003923
3924 /* duplicated tx_seq */
3925 if (tx_seq_offset < expected_tx_seq_offset)
3926 goto drop;
3927
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003928 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003929
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003930 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003931
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003932 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003933 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003934
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003935 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003936 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003937
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003938 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003939
Szymon Jancaef89f22011-11-16 09:32:18 +01003940 err = l2cap_send_srejframe(chan, tx_seq);
3941 if (err < 0) {
3942 l2cap_send_disconn_req(chan->conn, chan, -err);
3943 return err;
3944 }
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003945
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003946 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003947 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003948 return 0;
3949
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003950expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003951 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003952
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003953 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003954 bt_cb(skb)->tx_seq = tx_seq;
3955 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003956 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003957 return 0;
3958 }
3959
Mat Martineau84084a32011-07-22 14:54:00 -07003960 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003961 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
3962
Mat Martineaue3281402011-07-07 09:39:02 -07003963 if (err < 0) {
3964 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3965 return err;
3966 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003967
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003968 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003969 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003970 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003971 }
3972
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003973
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003974 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3975 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003976 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03003977 else
3978 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003979
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003980 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003981
3982drop:
3983 kfree_skb(skb);
3984 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003985}
3986
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003987static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003988{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003989 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003990 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003991
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003992 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003993 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003994
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003995 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003996 set_bit(CONN_SEND_FBIT, &chan->conn_state);
3997 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
3998 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003999 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004000 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004001
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004002 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004003 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004004 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004005 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004006 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004007
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004008 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004009 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004010
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004011 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004012 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004013
4014 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004015 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004016 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004017 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004018
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004019 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4020 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004021 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004022 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004023 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004024 }
4025}
4026
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004027static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004028{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004029 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004030
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004031 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004032
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004033 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004034
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004035 chan->expected_ack_seq = tx_seq;
4036 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004037
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004038 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004039 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004040 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004041 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004042 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004043
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004044 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4045 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004046 }
4047}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004048static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004049{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004050 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004051
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004052 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004053
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004054 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004055
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004056 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004057 chan->expected_ack_seq = tx_seq;
4058 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004059
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004060 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004061 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004062
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004063 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004064
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004065 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004066 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004067 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004068 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004069 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004070 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004071 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004072 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004073 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004074 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004075 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004076 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004077 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004078 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004079 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004080 }
4081 }
4082}
4083
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004084static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004085{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004086 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004087
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004088 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004089
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004090 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004091 chan->expected_ack_seq = tx_seq;
4092 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004093
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004094 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004095 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004096
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004097 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004098 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004099 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004100 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004101 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004102 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004103
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004104 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004105 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004106 } else {
4107 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4108 l2cap_send_sframe(chan, rx_control);
4109 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004110}
4111
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004112static 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 -03004113{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004114 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004115
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004116 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004117 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004118 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004119 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004120 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004121 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004122 }
4123
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004124 switch (__get_ctrl_super(chan, rx_control)) {
4125 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004126 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004127 break;
4128
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004129 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004130 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004131 break;
4132
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004133 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004134 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004135 break;
4136
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004137 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004138 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004139 break;
4140 }
4141
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004142 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004143 return 0;
4144}
4145
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004146static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
4147{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004148 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004149 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004150 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004151 int len, next_tx_seq_offset, req_seq_offset;
4152
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004153 control = __get_control(chan, skb->data);
4154 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004155 len = skb->len;
4156
4157 /*
4158 * We can just drop the corrupted I-frame here.
4159 * Receiver will miss it and start proper recovery
4160 * procedures and ask retransmission.
4161 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004162 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004163 goto drop;
4164
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004165 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004166 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004167
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004168 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004169 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004170
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004171 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004172 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004173 goto drop;
4174 }
4175
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004176 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004177
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004178 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4179
4180 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4181 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004182
4183 /* check for invalid req-seq */
4184 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004185 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004186 goto drop;
4187 }
4188
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004189 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004190 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004191 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004192 goto drop;
4193 }
4194
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004195 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004196 } else {
4197 if (len != 0) {
4198 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004199 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004200 goto drop;
4201 }
4202
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004203 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004204 }
4205
4206 return 0;
4207
4208drop:
4209 kfree_skb(skb);
4210 return 0;
4211}
4212
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4214{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004215 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07004216 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004217 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004218 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004219 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004221 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004222 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 BT_DBG("unknown cid 0x%4.4x", cid);
4224 goto drop;
4225 }
4226
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004227 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004228
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004229 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004231 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232 goto drop;
4233
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004234 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004235 case L2CAP_MODE_BASIC:
4236 /* If socket recv buffers overflows we drop data here
4237 * which is *bad* because L2CAP has to be reliable.
4238 * But we don't have any other choice. L2CAP doesn't
4239 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004241 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004242 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004244 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004245 goto done;
4246 break;
4247
4248 case L2CAP_MODE_ERTM:
Gustavo F. Padovaneb403a12011-06-24 01:54:50 -03004249 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004250
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004251 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004252
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004253 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004254 control = __get_control(chan, skb->data);
4255 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004256 len = skb->len;
4257
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004258 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004259 goto drop;
4260
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004261 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004262 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004263
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004264 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004265 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004266
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004267 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004268 goto drop;
4269
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004270 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004271
Mat Martineau84084a32011-07-22 14:54:00 -07004272 if (chan->expected_tx_seq != tx_seq) {
4273 /* Frame(s) missing - must discard partial SDU */
4274 kfree_skb(chan->sdu);
4275 chan->sdu = NULL;
4276 chan->sdu_last_frag = NULL;
4277 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004278
Mat Martineau84084a32011-07-22 14:54:00 -07004279 /* TODO: Notify userland of missing data */
4280 }
4281
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004282 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004283
4284 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4285 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004286
4287 goto done;
4288
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004289 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004290 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004291 break;
4292 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004293
4294drop:
4295 kfree_skb(skb);
4296
4297done:
Marcel Holtmann01394182006-07-03 10:02:46 +02004298 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004299 release_sock(sk);
Marcel Holtmann01394182006-07-03 10:02:46 +02004300
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 return 0;
4302}
4303
Al Viro8e036fc2007-07-29 00:16:36 -07004304static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004306 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004307 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004309 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4310 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 goto drop;
4312
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004313 sk = chan->sk;
4314
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004315 lock_sock(sk);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00004316
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 BT_DBG("sk %p, len %d", sk, skb->len);
4318
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004319 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 goto drop;
4321
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004322 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 goto drop;
4324
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004325 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 goto done;
4327
4328drop:
4329 kfree_skb(skb);
4330
4331done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004332 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004333 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 return 0;
4335}
4336
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004337static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4338{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004339 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004340 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004341
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004342 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4343 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004344 goto drop;
4345
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004346 sk = chan->sk;
4347
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004348 lock_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004349
4350 BT_DBG("sk %p, len %d", sk, skb->len);
4351
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004352 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004353 goto drop;
4354
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004355 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004356 goto drop;
4357
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004358 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004359 goto done;
4360
4361drop:
4362 kfree_skb(skb);
4363
4364done:
4365 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004366 release_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004367 return 0;
4368}
4369
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4371{
4372 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004373 u16 cid, len;
4374 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375
4376 skb_pull(skb, L2CAP_HDR_SIZE);
4377 cid = __le16_to_cpu(lh->cid);
4378 len = __le16_to_cpu(lh->len);
4379
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004380 if (len != skb->len) {
4381 kfree_skb(skb);
4382 return;
4383 }
4384
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4386
4387 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004388 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004389 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 l2cap_sig_channel(conn, skb);
4391 break;
4392
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004393 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004394 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 skb_pull(skb, 2);
4396 l2cap_conless_channel(conn, psm, skb);
4397 break;
4398
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004399 case L2CAP_CID_LE_DATA:
4400 l2cap_att_channel(conn, cid, skb);
4401 break;
4402
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004403 case L2CAP_CID_SMP:
4404 if (smp_sig_channel(conn, skb))
4405 l2cap_conn_del(conn->hcon, EACCES);
4406 break;
4407
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408 default:
4409 l2cap_data_channel(conn, cid, skb);
4410 break;
4411 }
4412}
4413
4414/* ---- L2CAP interface with lower layer (HCI) ---- */
4415
4416static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4417{
4418 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004419 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420
4421 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004422 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423
4424 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4425
4426 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004427 read_lock(&chan_list_lock);
4428 list_for_each_entry(c, &chan_list, global_l) {
4429 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004430
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004431 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 continue;
4433
4434 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004435 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004436 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004437 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004439 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4440 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004441 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004442 lm2 |= HCI_LM_MASTER;
4443 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004445 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446
4447 return exact ? lm1 : lm2;
4448}
4449
4450static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4451{
Marcel Holtmann01394182006-07-03 10:02:46 +02004452 struct l2cap_conn *conn;
4453
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4455
Ville Tervoacd7d372011-02-10 22:38:49 -03004456 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004457 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458
4459 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 conn = l2cap_conn_add(hcon, status);
4461 if (conn)
4462 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004463 } else
Joe Perchese1750722011-06-29 18:18:29 -07004464 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004465
4466 return 0;
4467}
4468
Marcel Holtmann2950f212009-02-12 14:02:50 +01004469static int l2cap_disconn_ind(struct hci_conn *hcon)
4470{
4471 struct l2cap_conn *conn = hcon->l2cap_data;
4472
4473 BT_DBG("hcon %p", hcon);
4474
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004475 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004476 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004477
4478 return conn->disc_reason;
4479}
4480
4481static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482{
4483 BT_DBG("hcon %p reason %d", hcon, reason);
4484
Ville Tervoacd7d372011-02-10 22:38:49 -03004485 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004486 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487
Joe Perchese1750722011-06-29 18:18:29 -07004488 l2cap_conn_del(hcon, bt_to_errno(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004489
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 return 0;
4491}
4492
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004493static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004494{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004495 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004496 return;
4497
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004498 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004499 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004500 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004501 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004502 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004503 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004504 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004505 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004506 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004507 }
4508}
4509
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004510static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004512 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004513 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514
Marcel Holtmann01394182006-07-03 10:02:46 +02004515 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004517
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 BT_DBG("conn %p", conn);
4519
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004520 if (hcon->type == LE_LINK) {
4521 smp_distribute_keys(conn, 0);
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02004522 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004523 }
4524
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004525 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004527 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004528 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004529
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 bh_lock_sock(sk);
4531
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004532 BT_DBG("chan->scid %d", chan->scid);
4533
4534 if (chan->scid == L2CAP_CID_LE_DATA) {
4535 if (!status && encrypt) {
4536 chan->sec_level = hcon->sec_level;
4537 l2cap_chan_ready(sk);
4538 }
4539
4540 bh_unlock_sock(sk);
4541 continue;
4542 }
4543
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004544 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004545 bh_unlock_sock(sk);
4546 continue;
4547 }
4548
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004549 if (!status && (chan->state == BT_CONNECTED ||
4550 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004551 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004552 bh_unlock_sock(sk);
4553 continue;
4554 }
4555
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004556 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004557 if (!status) {
4558 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004559 req.scid = cpu_to_le16(chan->scid);
4560 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004561
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004562 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004563 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004564
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004565 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004566 L2CAP_CONN_REQ, sizeof(req), &req);
4567 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004568 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004569 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004570 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004571 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004572 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004573 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004574
4575 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004576 if (bt_sk(sk)->defer_setup) {
4577 struct sock *parent = bt_sk(sk)->parent;
4578 res = L2CAP_CR_PEND;
4579 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004580 if (parent)
4581 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004582 } else {
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004583 l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004584 res = L2CAP_CR_SUCCESS;
4585 stat = L2CAP_CS_NO_INFO;
4586 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004587 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004588 l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004589 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004590 res = L2CAP_CR_SEC_BLOCK;
4591 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004592 }
4593
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004594 rsp.scid = cpu_to_le16(chan->dcid);
4595 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004596 rsp.result = cpu_to_le16(res);
4597 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004598 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4599 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600 }
4601
Linus Torvalds1da177e2005-04-16 15:20:36 -07004602 bh_unlock_sock(sk);
4603 }
4604
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004605 rcu_read_unlock();
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004606
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 return 0;
4608}
4609
4610static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4611{
4612 struct l2cap_conn *conn = hcon->l2cap_data;
4613
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004614 if (!conn)
4615 conn = l2cap_conn_add(hcon, 0);
4616
4617 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 goto drop;
4619
4620 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4621
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004622 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004624 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004625 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 int len;
4627
4628 if (conn->rx_len) {
4629 BT_ERR("Unexpected start frame (len %d)", skb->len);
4630 kfree_skb(conn->rx_skb);
4631 conn->rx_skb = NULL;
4632 conn->rx_len = 0;
4633 l2cap_conn_unreliable(conn, ECOMM);
4634 }
4635
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004636 /* Start fragment always begin with Basic L2CAP header */
4637 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 BT_ERR("Frame is too short (len %d)", skb->len);
4639 l2cap_conn_unreliable(conn, ECOMM);
4640 goto drop;
4641 }
4642
4643 hdr = (struct l2cap_hdr *) skb->data;
4644 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004645 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646
4647 if (len == skb->len) {
4648 /* Complete frame received */
4649 l2cap_recv_frame(conn, skb);
4650 return 0;
4651 }
4652
4653 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4654
4655 if (skb->len > len) {
4656 BT_ERR("Frame is too long (len %d, expected len %d)",
4657 skb->len, len);
4658 l2cap_conn_unreliable(conn, ECOMM);
4659 goto drop;
4660 }
4661
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004662 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004663
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004664 if (chan && chan->sk) {
4665 struct sock *sk = chan->sk;
4666
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004667 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004668 BT_ERR("Frame exceeding recv MTU (len %d, "
4669 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004670 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004671 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004672 l2cap_conn_unreliable(conn, ECOMM);
4673 goto drop;
4674 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004675 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004676 }
4677
Linus Torvalds1da177e2005-04-16 15:20:36 -07004678 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004679 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4680 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004681 goto drop;
4682
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004683 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004684 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 conn->rx_len = len - skb->len;
4686 } else {
4687 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4688
4689 if (!conn->rx_len) {
4690 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4691 l2cap_conn_unreliable(conn, ECOMM);
4692 goto drop;
4693 }
4694
4695 if (skb->len > conn->rx_len) {
4696 BT_ERR("Fragment is too long (len %d, expected %d)",
4697 skb->len, conn->rx_len);
4698 kfree_skb(conn->rx_skb);
4699 conn->rx_skb = NULL;
4700 conn->rx_len = 0;
4701 l2cap_conn_unreliable(conn, ECOMM);
4702 goto drop;
4703 }
4704
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004705 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004706 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004707 conn->rx_len -= skb->len;
4708
4709 if (!conn->rx_len) {
4710 /* Complete frame received */
4711 l2cap_recv_frame(conn, conn->rx_skb);
4712 conn->rx_skb = NULL;
4713 }
4714 }
4715
4716drop:
4717 kfree_skb(skb);
4718 return 0;
4719}
4720
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004721static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004723 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004725 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004727 list_for_each_entry(c, &chan_list, global_l) {
4728 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004730 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 +01004731 batostr(&bt_sk(sk)->src),
4732 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004733 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004734 c->scid, c->dcid, c->imtu, c->omtu,
4735 c->sec_level, c->mode);
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004736}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004738 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004739
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004740 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741}
4742
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004743static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4744{
4745 return single_open(file, l2cap_debugfs_show, inode->i_private);
4746}
4747
4748static const struct file_operations l2cap_debugfs_fops = {
4749 .open = l2cap_debugfs_open,
4750 .read = seq_read,
4751 .llseek = seq_lseek,
4752 .release = single_release,
4753};
4754
4755static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757static struct hci_proto l2cap_hci_proto = {
4758 .name = "L2CAP",
4759 .id = HCI_PROTO_L2CAP,
4760 .connect_ind = l2cap_connect_ind,
4761 .connect_cfm = l2cap_connect_cfm,
4762 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004763 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004764 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765 .recv_acldata = l2cap_recv_acldata
4766};
4767
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004768int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769{
4770 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004771
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004772 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 if (err < 0)
4774 return err;
4775
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 err = hci_register_proto(&l2cap_hci_proto);
4777 if (err < 0) {
4778 BT_ERR("L2CAP protocol registration failed");
4779 bt_sock_unregister(BTPROTO_L2CAP);
4780 goto error;
4781 }
4782
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004783 if (bt_debugfs) {
4784 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4785 bt_debugfs, NULL, &l2cap_debugfs_fops);
4786 if (!l2cap_debugfs)
4787 BT_ERR("Failed to create L2CAP debug file");
4788 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 return 0;
4791
4792error:
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004793 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 return err;
4795}
4796
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004797void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004799 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800
Linus Torvalds1da177e2005-04-16 15:20:36 -07004801 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4802 BT_ERR("L2CAP protocol unregistration failed");
4803
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004804 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805}
4806
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004807module_param(disable_ertm, bool, 0644);
4808MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");