blob: f1a6b3cbdba7aed5eb1ead7568b24ca0e7ac6188 [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
Rusty Russelleb939922011-12-19 14:08:01 +000060bool 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
Marcel Holtmann01394182006-07-03 10:02:46 +020076/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030077
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030078static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020079{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020080 struct l2cap_chan *c, *r = NULL;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030081
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020082 rcu_read_lock();
83
84 list_for_each_entry_rcu(c, &conn->chan_l, list) {
85 if (c->dcid == cid) {
86 r = c;
87 break;
88 }
Marcel Holtmann01394182006-07-03 10:02:46 +020089 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020090
91 rcu_read_unlock();
92 return r;
Marcel Holtmann01394182006-07-03 10:02:46 +020093}
94
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030095static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020096{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020097 struct l2cap_chan *c, *r = NULL;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030098
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020099 rcu_read_lock();
100
101 list_for_each_entry_rcu(c, &conn->chan_l, list) {
102 if (c->scid == cid) {
103 r = c;
104 break;
105 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200106 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200107
108 rcu_read_unlock();
109 return r;
Marcel Holtmann01394182006-07-03 10:02:46 +0200110}
111
112/* Find channel with given SCID.
113 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300114static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200115{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300116 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300117
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300118 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300119 if (c)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300120 lock_sock(c->sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300121 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200122}
123
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300124static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200125{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200126 struct l2cap_chan *c, *r = NULL;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300127
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200128 rcu_read_lock();
129
130 list_for_each_entry_rcu(c, &conn->chan_l, list) {
131 if (c->ident == ident) {
132 r = c;
133 break;
134 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200135 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200136
137 rcu_read_unlock();
138 return r;
Marcel Holtmann01394182006-07-03 10:02:46 +0200139}
140
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300141static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200142{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300143 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300144
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300145 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300146 if (c)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300147 lock_sock(c->sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300148 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200149}
150
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300151static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300152{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300153 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300154
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300155 list_for_each_entry(c, &chan_list, global_l) {
156 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100157 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300158 }
Szymon Janc250938c2011-11-16 09:32:22 +0100159 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300160}
161
162int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
163{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300164 int err;
165
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200166 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300167
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300168 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300169 err = -EADDRINUSE;
170 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300171 }
172
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300173 if (psm) {
174 chan->psm = psm;
175 chan->sport = psm;
176 err = 0;
177 } else {
178 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300179
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300180 err = -EINVAL;
181 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300182 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300183 chan->psm = cpu_to_le16(p);
184 chan->sport = cpu_to_le16(p);
185 err = 0;
186 break;
187 }
188 }
189
190done:
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200191 write_unlock(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300192 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300193}
194
195int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
196{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200197 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300198
199 chan->scid = scid;
200
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200201 write_unlock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300202
203 return 0;
204}
205
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300206static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200207{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300208 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200209
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300210 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300211 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200212 return cid;
213 }
214
215 return 0;
216}
217
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200218static char *state_to_string(int state)
219{
220 switch(state) {
221 case BT_CONNECTED:
222 return "BT_CONNECTED";
223 case BT_OPEN:
224 return "BT_OPEN";
225 case BT_BOUND:
226 return "BT_BOUND";
227 case BT_LISTEN:
228 return "BT_LISTEN";
229 case BT_CONNECT:
230 return "BT_CONNECT";
231 case BT_CONNECT2:
232 return "BT_CONNECT2";
233 case BT_CONFIG:
234 return "BT_CONFIG";
235 case BT_DISCONN:
236 return "BT_DISCONN";
237 case BT_CLOSED:
238 return "BT_CLOSED";
239 }
240
241 return "invalid state";
242}
243
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300244static void l2cap_state_change(struct l2cap_chan *chan, int state)
245{
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200246 BT_DBG("%p %s -> %s", chan, state_to_string(chan->state),
247 state_to_string(state));
248
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300249 chan->state = state;
250 chan->ops->state_change(chan->data, state);
251}
252
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300253static void l2cap_chan_timeout(struct work_struct *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300254{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300255 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
256 chan_timer.work);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300257 struct sock *sk = chan->sk;
258 int reason;
259
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300260 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300261
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300262 lock_sock(sk);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300263
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300264 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300265 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300266 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300267 chan->sec_level != BT_SECURITY_SDP)
268 reason = ECONNREFUSED;
269 else
270 reason = ETIMEDOUT;
271
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300272 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300273
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300274 release_sock(sk);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300275
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300276 chan->ops->close(chan->data);
Ulisses Furquim371fd832011-12-21 20:02:36 -0200277 l2cap_chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300278}
279
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300280struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200281{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300282 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200283
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300284 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
285 if (!chan)
286 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200287
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300288 chan->sk = sk;
289
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200290 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300291 list_add(&chan->global_l, &chan_list);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200292 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300293
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300294 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300295
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300296 chan->state = BT_OPEN;
297
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300298 atomic_set(&chan->refcnt, 1);
299
Szymon Jancabc545b2011-11-03 16:05:44 +0100300 BT_DBG("sk %p chan %p", sk, chan);
301
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300302 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200303}
304
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300305void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300306{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200307 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300308 list_del(&chan->global_l);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200309 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300310
Ulisses Furquim371fd832011-12-21 20:02:36 -0200311 l2cap_chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300312}
313
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200314static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200315{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300316 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300317 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200318
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200319 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100320
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300321 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200322
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200323 switch (chan->chan_type) {
324 case L2CAP_CHAN_CONN_ORIENTED:
Ville Tervob62f3282011-02-10 22:38:50 -0300325 if (conn->hcon->type == LE_LINK) {
326 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300327 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300328 chan->scid = L2CAP_CID_LE_DATA;
329 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300330 } else {
331 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300332 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300333 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300334 }
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200335 break;
336
337 case L2CAP_CHAN_CONN_LESS:
Marcel Holtmann01394182006-07-03 10:02:46 +0200338 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300339 chan->scid = L2CAP_CID_CONN_LESS;
340 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300341 chan->omtu = L2CAP_DEFAULT_MTU;
Andrei Emeltchenko54911202012-02-06 15:04:00 +0200342 break;
343
344 default:
Marcel Holtmann01394182006-07-03 10:02:46 +0200345 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300346 chan->scid = L2CAP_CID_SIGNALING;
347 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300348 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200349 }
350
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300351 chan->local_id = L2CAP_BESTEFFORT_ID;
352 chan->local_stype = L2CAP_SERV_BESTEFFORT;
353 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
354 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
355 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
356 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
357
Ulisses Furquim371fd832011-12-21 20:02:36 -0200358 l2cap_chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300359
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200360 list_add_rcu(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200361}
362
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900363/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200364 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300365static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200366{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300367 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300368 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200369 struct sock *parent = bt_sk(sk)->parent;
370
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300371 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200372
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300373 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200374
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900375 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300376 /* Delete from channel list */
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200377 list_del_rcu(&chan->list);
378 synchronize_rcu();
379
Ulisses Furquim371fd832011-12-21 20:02:36 -0200380 l2cap_chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300381
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300382 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200383 hci_conn_put(conn->hcon);
384 }
385
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300386 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200387 sock_set_flag(sk, SOCK_ZAPPED);
388
389 if (err)
390 sk->sk_err = err;
391
392 if (parent) {
393 bt_accept_unlink(sk);
394 parent->sk_data_ready(parent, 0);
395 } else
396 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300397
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300398 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
399 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300400 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300401
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300402 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300403
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300404 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300405 struct srej_list *l, *tmp;
406
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300407 __clear_retrans_timer(chan);
408 __clear_monitor_timer(chan);
409 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300410
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300411 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300412
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300413 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300414 list_del(&l->list);
415 kfree(l);
416 }
417 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200418}
419
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300420static void l2cap_chan_cleanup_listen(struct sock *parent)
421{
422 struct sock *sk;
423
424 BT_DBG("parent %p", parent);
425
426 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300427 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300428 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300429 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300430 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300431 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300432 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300433 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300434 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300435}
436
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300437void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300438{
439 struct l2cap_conn *conn = chan->conn;
440 struct sock *sk = chan->sk;
441
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300442 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300443
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300444 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300445 case BT_LISTEN:
446 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300447
448 l2cap_state_change(chan, BT_CLOSED);
449 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300450 break;
451
452 case BT_CONNECTED:
453 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300454 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300455 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300456 __clear_chan_timer(chan);
457 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300458 l2cap_send_disconn_req(conn, chan, reason);
459 } else
460 l2cap_chan_del(chan, reason);
461 break;
462
463 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300464 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300465 conn->hcon->type == ACL_LINK) {
466 struct l2cap_conn_rsp rsp;
467 __u16 result;
468
469 if (bt_sk(sk)->defer_setup)
470 result = L2CAP_CR_SEC_BLOCK;
471 else
472 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300473 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300474
475 rsp.scid = cpu_to_le16(chan->dcid);
476 rsp.dcid = cpu_to_le16(chan->scid);
477 rsp.result = cpu_to_le16(result);
478 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
479 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
480 sizeof(rsp), &rsp);
481 }
482
483 l2cap_chan_del(chan, reason);
484 break;
485
486 case BT_CONNECT:
487 case BT_DISCONN:
488 l2cap_chan_del(chan, reason);
489 break;
490
491 default:
492 sock_set_flag(sk, SOCK_ZAPPED);
493 break;
494 }
495}
496
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300497static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530498{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300499 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300500 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530501 case BT_SECURITY_HIGH:
502 return HCI_AT_DEDICATED_BONDING_MITM;
503 case BT_SECURITY_MEDIUM:
504 return HCI_AT_DEDICATED_BONDING;
505 default:
506 return HCI_AT_NO_BONDING;
507 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300508 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300509 if (chan->sec_level == BT_SECURITY_LOW)
510 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530511
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300512 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530513 return HCI_AT_NO_BONDING_MITM;
514 else
515 return HCI_AT_NO_BONDING;
516 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300517 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530518 case BT_SECURITY_HIGH:
519 return HCI_AT_GENERAL_BONDING_MITM;
520 case BT_SECURITY_MEDIUM:
521 return HCI_AT_GENERAL_BONDING;
522 default:
523 return HCI_AT_NO_BONDING;
524 }
525 }
526}
527
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200528/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200529int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200530{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300531 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100532 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200533
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300534 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100535
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300536 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200537}
538
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200539static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200540{
541 u8 id;
542
543 /* Get next available identificator.
544 * 1 - 128 are used by kernel.
545 * 129 - 199 are reserved.
546 * 200 - 254 are used by utilities like l2ping, etc.
547 */
548
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200549 spin_lock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200550
551 if (++conn->tx_ident > 128)
552 conn->tx_ident = 1;
553
554 id = conn->tx_ident;
555
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200556 spin_unlock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200557
558 return id;
559}
560
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300561static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200562{
563 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200564 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200565
566 BT_DBG("code 0x%2.2x", code);
567
568 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300569 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200570
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200571 if (lmp_no_flush_capable(conn->hcon->hdev))
572 flags = ACL_START_NO_FLUSH;
573 else
574 flags = ACL_START;
575
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700576 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200577 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700578
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200579 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200580}
581
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200582static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
583{
584 struct hci_conn *hcon = chan->conn->hcon;
585 u16 flags;
586
587 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
588 skb->priority);
589
590 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
591 lmp_no_flush_capable(hcon->hdev))
592 flags = ACL_START_NO_FLUSH;
593 else
594 flags = ACL_START;
595
596 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
597 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598}
599
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300600static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300601{
602 struct sk_buff *skb;
603 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300604 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300605 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300606
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300607 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300608 return;
609
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300610 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
611 hlen = L2CAP_EXT_HDR_SIZE;
612 else
613 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300614
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300615 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300616 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300617
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300618 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300619
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300620 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300621
622 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300623
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300624 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300625 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300626
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300627 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300628 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300629
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300630 skb = bt_skb_alloc(count, GFP_ATOMIC);
631 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300632 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300633
634 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300635 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300636 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300637
638 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300639
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300640 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300641 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
642 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300643 }
644
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200645 skb->priority = HCI_PRIO_MAX;
646 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300647}
648
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300649static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300650{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300651 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300652 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300653 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300654 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300655 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300656
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300657 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300658
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300659 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300660}
661
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300662static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300663{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300664 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300665}
666
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300667static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200668{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300669 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200670
671 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100672 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
673 return;
674
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200675 if (l2cap_chan_check_security(chan) &&
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300676 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200677 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300678 req.scid = cpu_to_le16(chan->scid);
679 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200680
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300681 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300682 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200683
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300684 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
685 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200686 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200687 } else {
688 struct l2cap_info_req req;
689 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
690
691 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
692 conn->info_ident = l2cap_get_ident(conn);
693
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200694 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200695 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
696
697 l2cap_send_cmd(conn, conn->info_ident,
698 L2CAP_INFO_REQ, sizeof(req), &req);
699 }
700}
701
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300702static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
703{
704 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300705 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300706 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
707
708 switch (mode) {
709 case L2CAP_MODE_ERTM:
710 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
711 case L2CAP_MODE_STREAMING:
712 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
713 default:
714 return 0x00;
715 }
716}
717
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300718static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300719{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300720 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300721 struct l2cap_disconn_req req;
722
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300723 if (!conn)
724 return;
725
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300726 sk = chan->sk;
727
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300728 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300729 __clear_retrans_timer(chan);
730 __clear_monitor_timer(chan);
731 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300732 }
733
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300734 req.dcid = cpu_to_le16(chan->dcid);
735 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300736 l2cap_send_cmd(conn, l2cap_get_ident(conn),
737 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300738
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300739 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300740 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300741}
742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200744static void l2cap_conn_start(struct l2cap_conn *conn)
745{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200746 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200747
748 BT_DBG("conn %p", conn);
749
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200750 rcu_read_lock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200751
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200752 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300753 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300754
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200755 bh_lock_sock(sk);
756
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300757 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200758 bh_unlock_sock(sk);
759 continue;
760 }
761
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300762 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300763 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300764
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200765 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300766 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300767 bh_unlock_sock(sk);
768 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200769 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300770
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300771 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
772 && test_bit(CONF_STATE2_DEVICE,
773 &chan->conf_state)) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300774 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300775 * so release the lock */
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300776 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300777 bh_unlock_sock(sk);
778 continue;
779 }
780
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300781 req.scid = cpu_to_le16(chan->scid);
782 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300783
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300784 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300785 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300786
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300787 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
788 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300789
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300790 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200791 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300792 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300793 rsp.scid = cpu_to_le16(chan->dcid);
794 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200795
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200796 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100797 if (bt_sk(sk)->defer_setup) {
798 struct sock *parent = bt_sk(sk)->parent;
799 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
800 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000801 if (parent)
802 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100803
804 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300805 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100806 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
807 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
808 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200809 } else {
810 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
811 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
812 }
813
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300814 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
815 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300816
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300817 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300818 rsp.result != L2CAP_CR_SUCCESS) {
819 bh_unlock_sock(sk);
820 continue;
821 }
822
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300823 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300824 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300825 l2cap_build_conf_req(chan, buf), buf);
826 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200827 }
828
829 bh_unlock_sock(sk);
830 }
831
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200832 rcu_read_unlock();
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200833}
834
Ville Tervob62f3282011-02-10 22:38:50 -0300835/* Find socket with cid and source bdaddr.
836 * Returns closest match, locked.
837 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300838static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300839{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300840 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300841
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300842 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300843
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300844 list_for_each_entry(c, &chan_list, global_l) {
845 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300846
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300847 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300848 continue;
849
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300850 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300851 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300852 if (!bacmp(&bt_sk(sk)->src, src)) {
853 read_unlock(&chan_list_lock);
854 return c;
855 }
Ville Tervob62f3282011-02-10 22:38:50 -0300856
857 /* Closest match */
858 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300859 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300860 }
861 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300862
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300863 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300864
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300865 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300866}
867
868static void l2cap_le_conn_ready(struct l2cap_conn *conn)
869{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300870 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300871 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300872
873 BT_DBG("");
874
875 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300876 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300877 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300878 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300879 return;
880
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300881 parent = pchan->sk;
882
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300883 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300884
Ville Tervob62f3282011-02-10 22:38:50 -0300885 /* Check for backlog size */
886 if (sk_acceptq_is_full(parent)) {
887 BT_DBG("backlog full %d", parent->sk_ack_backlog);
888 goto clean;
889 }
890
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300891 chan = pchan->ops->new_connection(pchan->data);
892 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300893 goto clean;
894
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300895 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300896
Ville Tervob62f3282011-02-10 22:38:50 -0300897 hci_conn_hold(conn->hcon);
898
Ville Tervob62f3282011-02-10 22:38:50 -0300899 bacpy(&bt_sk(sk)->src, conn->src);
900 bacpy(&bt_sk(sk)->dst, conn->dst);
901
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300902 bt_accept_enqueue(parent, sk);
903
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200904 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300905
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300906 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300907
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300908 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300909 parent->sk_data_ready(parent, 0);
910
Ville Tervob62f3282011-02-10 22:38:50 -0300911clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300912 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300913}
914
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200915static void l2cap_chan_ready(struct l2cap_chan *chan)
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300916{
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200917 struct sock *sk = chan->sk;
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300918 struct sock *parent = bt_sk(sk)->parent;
919
920 BT_DBG("sk %p, parent %p", sk, parent);
921
922 chan->conf_state = 0;
923 __clear_chan_timer(chan);
924
Vinicius Costa Gomes43f3dc42011-06-20 18:53:18 -0300925 l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300926 sk->sk_state_change(sk);
927
928 if (parent)
929 parent->sk_data_ready(parent, 0);
930}
931
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200932static void l2cap_conn_ready(struct l2cap_conn *conn)
933{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300934 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200935
936 BT_DBG("conn %p", conn);
937
Ville Tervob62f3282011-02-10 22:38:50 -0300938 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
939 l2cap_le_conn_ready(conn);
940
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300941 if (conn->hcon->out && conn->hcon->type == LE_LINK)
942 smp_conn_security(conn, conn->hcon->pending_sec_level);
943
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200944 rcu_read_lock();
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200945
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200946 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300947 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300948
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200949 bh_lock_sock(sk);
950
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300951 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300952 if (smp_conn_security(conn, chan->sec_level))
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +0200953 l2cap_chan_ready(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300954
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300955 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300956 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300957 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200958 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300959
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300960 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300961 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200962
963 bh_unlock_sock(sk);
964 }
965
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200966 rcu_read_unlock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200967}
968
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200969/* Notify sockets that we cannot guaranty reliability anymore */
970static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
971{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300972 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200973
974 BT_DBG("conn %p", conn);
975
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200976 rcu_read_lock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200977
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200978 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300979 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300980
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300981 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200982 sk->sk_err = err;
983 }
984
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200985 rcu_read_unlock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200986}
987
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200988static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200989{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200990 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200991 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200992
Marcel Holtmann984947d2009-02-06 23:35:19 +0100993 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100994 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100995
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200996 l2cap_conn_start(conn);
997}
998
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300999static void l2cap_conn_del(struct hci_conn *hcon, int err)
1000{
1001 struct l2cap_conn *conn = hcon->l2cap_data;
1002 struct l2cap_chan *chan, *l;
1003 struct sock *sk;
1004
1005 if (!conn)
1006 return;
1007
1008 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1009
1010 kfree_skb(conn->rx_skb);
1011
1012 /* Kill channels */
1013 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
1014 sk = chan->sk;
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03001015 lock_sock(sk);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001016 l2cap_chan_del(chan, err);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03001017 release_sock(sk);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001018 chan->ops->close(chan->data);
1019 }
1020
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001021 hci_chan_del(conn->hchan);
1022
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001023 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim127074b2012-01-30 18:26:29 -02001024 cancel_delayed_work_sync(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001025
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001026 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim127074b2012-01-30 18:26:29 -02001027 cancel_delayed_work_sync(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001028 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001029 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001030
1031 hcon->l2cap_data = NULL;
1032 kfree(conn);
1033}
1034
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001035static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001036{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001037 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1038 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001039
1040 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1041}
1042
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1044{
Marcel Holtmann01394182006-07-03 10:02:46 +02001045 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001046 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
Marcel Holtmann01394182006-07-03 10:02:46 +02001048 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 return conn;
1050
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001051 hchan = hci_chan_create(hcon);
1052 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001055 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1056 if (!conn) {
1057 hci_chan_del(hchan);
1058 return NULL;
1059 }
1060
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 hcon->l2cap_data = conn;
1062 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001063 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001065 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001066
Ville Tervoacd7d372011-02-10 22:38:49 -03001067 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1068 conn->mtu = hcon->hdev->le_mtu;
1069 else
1070 conn->mtu = hcon->hdev->acl_mtu;
1071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 conn->src = &hcon->hdev->bdaddr;
1073 conn->dst = &hcon->dst;
1074
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001075 conn->feat_mask = 0;
1076
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001078
1079 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001081 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001082 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001083 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001084 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001085
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001086 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 return conn;
1089}
1090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
1093/* Find socket with psm and source bdaddr.
1094 * Returns closest match.
1095 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001096static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001098 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001100 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001101
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001102 list_for_each_entry(c, &chan_list, global_l) {
1103 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001104
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001105 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 continue;
1107
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001108 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001110 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001111 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001112 return c;
1113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
1115 /* Closest match */
1116 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001117 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 }
1119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001121 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001122
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001123 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124}
1125
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001126int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001128 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 struct l2cap_conn *conn;
1131 struct hci_conn *hcon;
1132 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001133 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001134 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001136 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001137 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001139 hdev = hci_get_route(dst, src);
1140 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 return -EHOSTUNREACH;
1142
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001143 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001145 lock_sock(sk);
1146
1147 /* PSM must be odd and lsb of upper byte must be 0 */
1148 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1149 chan->chan_type != L2CAP_CHAN_RAW) {
1150 err = -EINVAL;
1151 goto done;
1152 }
1153
1154 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1155 err = -EINVAL;
1156 goto done;
1157 }
1158
1159 switch (chan->mode) {
1160 case L2CAP_MODE_BASIC:
1161 break;
1162 case L2CAP_MODE_ERTM:
1163 case L2CAP_MODE_STREAMING:
1164 if (!disable_ertm)
1165 break;
1166 /* fall through */
1167 default:
1168 err = -ENOTSUPP;
1169 goto done;
1170 }
1171
1172 switch (sk->sk_state) {
1173 case BT_CONNECT:
1174 case BT_CONNECT2:
1175 case BT_CONFIG:
1176 /* Already connecting */
1177 err = 0;
1178 goto done;
1179
1180 case BT_CONNECTED:
1181 /* Already connected */
1182 err = -EISCONN;
1183 goto done;
1184
1185 case BT_OPEN:
1186 case BT_BOUND:
1187 /* Can connect */
1188 break;
1189
1190 default:
1191 err = -EBADFD;
1192 goto done;
1193 }
1194
1195 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001196 bacpy(&bt_sk(sk)->dst, dst);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001197 chan->psm = psm;
1198 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001200 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001201
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001202 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001203 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001204 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001205 else
1206 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001207 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001208
Ville Tervo30e76272011-02-22 16:10:53 -03001209 if (IS_ERR(hcon)) {
1210 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001212 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
1214 conn = l2cap_conn_add(hcon, 0);
1215 if (!conn) {
1216 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001217 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 goto done;
1219 }
1220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 /* Update source addr of the socket */
1222 bacpy(src, conn->src);
1223
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001224 l2cap_chan_add(conn, chan);
1225
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001226 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001227 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
1229 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001230 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001231 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001232 if (l2cap_chan_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001233 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001234 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001235 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 }
1237
Ville Tervo30e76272011-02-22 16:10:53 -03001238 err = 0;
1239
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001241 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 hci_dev_put(hdev);
1243 return err;
1244}
1245
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001246int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001247{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001248 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001249 DECLARE_WAITQUEUE(wait, current);
1250 int err = 0;
1251 int timeo = HZ/5;
1252
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001253 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001254 set_current_state(TASK_INTERRUPTIBLE);
1255 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001256 if (!timeo)
1257 timeo = HZ/5;
1258
1259 if (signal_pending(current)) {
1260 err = sock_intr_errno(timeo);
1261 break;
1262 }
1263
1264 release_sock(sk);
1265 timeo = schedule_timeout(timeo);
1266 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001267 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001268
1269 err = sock_error(sk);
1270 if (err)
1271 break;
1272 }
1273 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001274 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001275 return err;
1276}
1277
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001278static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001279{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001280 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1281 monitor_timer.work);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001282 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001283
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001284 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001285
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001286 lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001287 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001288 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001289 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001290 return;
1291 }
1292
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001293 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001294 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001295
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001296 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001297 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001298}
1299
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001300static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001301{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001302 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1303 retrans_timer.work);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001304 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001305
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001306 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001307
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001308 lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001309 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001310 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001311
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001312 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001313
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001314 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001315 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001316}
1317
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001318static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001319{
1320 struct sk_buff *skb;
1321
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001322 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001323 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001324 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001325 break;
1326
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001327 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001328 kfree_skb(skb);
1329
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001330 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001331 }
1332
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001333 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001334 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001335}
1336
Szymon Janc67c9e842011-07-28 16:24:33 +02001337static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001338{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001339 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001340 u32 control;
1341 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001342
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001343 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001344 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001345 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001346 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001347
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001348 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001349 fcs = crc16(0, (u8 *)skb->data,
1350 skb->len - L2CAP_FCS_SIZE);
1351 put_unaligned_le16(fcs,
1352 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001353 }
1354
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001355 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001356
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001357 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001358 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001359}
1360
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001361static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001362{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001363 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001364 u16 fcs;
1365 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001366
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001367 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001368 if (!skb)
1369 return;
1370
Szymon Jancd1726b62011-11-16 09:32:20 +01001371 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001372 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001373 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001374
Szymon Jancd1726b62011-11-16 09:32:20 +01001375 skb = skb_queue_next(&chan->tx_q, skb);
1376 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001377
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001378 if (chan->remote_max_tx &&
1379 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001380 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001381 return;
1382 }
1383
1384 tx_skb = skb_clone(skb, GFP_ATOMIC);
1385 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001386
1387 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001388 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001389
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001390 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001391 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001392
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001393 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001394 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001395
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001396 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001397
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001398 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001399 fcs = crc16(0, (u8 *)tx_skb->data,
1400 tx_skb->len - L2CAP_FCS_SIZE);
1401 put_unaligned_le16(fcs,
1402 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001403 }
1404
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001405 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001406}
1407
Szymon Janc67c9e842011-07-28 16:24:33 +02001408static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001409{
1410 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001411 u16 fcs;
1412 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001413 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001414
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001415 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001416 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001417
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001418 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001419
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001420 if (chan->remote_max_tx &&
1421 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001422 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001423 break;
1424 }
1425
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001426 tx_skb = skb_clone(skb, GFP_ATOMIC);
1427
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001428 bt_cb(skb)->retries++;
1429
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001430 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001431 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001432
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001433 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001434 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001435
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001436 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001437 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001438
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001439 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001440
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001441 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001442 fcs = crc16(0, (u8 *)skb->data,
1443 tx_skb->len - L2CAP_FCS_SIZE);
1444 put_unaligned_le16(fcs, skb->data +
1445 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001446 }
1447
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001448 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001449
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001450 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001451
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001452 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001453
1454 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001455
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301456 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001457 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301458
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001459 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001460
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001461 if (skb_queue_is_last(&chan->tx_q, skb))
1462 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001463 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001464 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001465
1466 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001467 }
1468
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001469 return nsent;
1470}
1471
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001472static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001473{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001474 int ret;
1475
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001476 if (!skb_queue_empty(&chan->tx_q))
1477 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001478
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001479 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001480 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001481 return ret;
1482}
1483
Szymon Jancb17e73b2012-01-11 10:59:47 +01001484static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001485{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001486 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001487
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001488 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001489
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001490 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001491 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001492 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001493 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001494 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001495 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001496
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001497 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001498 return;
1499
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001500 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001501 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001502}
1503
Szymon Jancb17e73b2012-01-11 10:59:47 +01001504static void l2cap_send_ack(struct l2cap_chan *chan)
1505{
1506 __clear_ack_timer(chan);
1507 __l2cap_send_ack(chan);
1508}
1509
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001510static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001511{
1512 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001513 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001514
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001515 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001516 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001517
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001518 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001519 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001520
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001521 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001522}
1523
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001524static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr *msg, int len, int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001526 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001527 struct sk_buff **frag;
1528 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001530 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001531 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532
1533 sent += count;
1534 len -= count;
1535
1536 /* Continuation fragments (no L2CAP header) */
1537 frag = &skb_shinfo(skb)->frag_list;
1538 while (len) {
1539 count = min_t(unsigned int, conn->mtu, len);
1540
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001541 *frag = chan->ops->alloc_skb(chan, count,
1542 msg->msg_flags & MSG_DONTWAIT, &err);
1543
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 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. Padovan8c1d7872011-04-13 20:23:55 -03001564 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001565 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001566 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001567 struct l2cap_hdr *lh;
1568
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001569 BT_DBG("chan %p len %d priority %u", chan, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001570
1571 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001572
1573 skb = chan->ops->alloc_skb(chan, count + hlen,
1574 msg->msg_flags & MSG_DONTWAIT, &err);
1575
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001576 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001577 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001578
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001579 skb->priority = priority;
1580
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001581 /* Create L2CAP header */
1582 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001583 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001584 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001585 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001586
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001587 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001588 if (unlikely(err < 0)) {
1589 kfree_skb(skb);
1590 return ERR_PTR(err);
1591 }
1592 return skb;
1593}
1594
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001595static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1596 struct msghdr *msg, size_t len,
1597 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001598{
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
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001604 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001605
1606 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001607
1608 skb = chan->ops->alloc_skb(chan, count + hlen,
1609 msg->msg_flags & MSG_DONTWAIT, &err);
1610
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001611 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001612 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001613
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001614 skb->priority = priority;
1615
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001616 /* Create L2CAP header */
1617 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001618 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001619 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1620
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001621 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001622 if (unlikely(err < 0)) {
1623 kfree_skb(skb);
1624 return ERR_PTR(err);
1625 }
1626 return skb;
1627}
1628
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001629static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1630 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001631 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001632{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001633 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001634 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001635 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001636 struct l2cap_hdr *lh;
1637
Andrei Emeltchenko6d5922b2012-02-06 15:04:01 +02001638 BT_DBG("chan %p len %d", chan, (int)len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001639
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001640 if (!conn)
1641 return ERR_PTR(-ENOTCONN);
1642
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001643 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1644 hlen = L2CAP_EXT_HDR_SIZE;
1645 else
1646 hlen = L2CAP_ENH_HDR_SIZE;
1647
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001648 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001649 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001650
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001651 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001652 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001653
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001654 count = min_t(unsigned int, (conn->mtu - hlen), len);
Andrei Emeltchenko2f7719c2012-01-20 14:08:03 +02001655
1656 skb = chan->ops->alloc_skb(chan, count + hlen,
1657 msg->msg_flags & MSG_DONTWAIT, &err);
1658
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001659 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001660 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001661
1662 /* Create L2CAP header */
1663 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001664 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001665 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001666
1667 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1668
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001669 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001670 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001671
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001672 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001673 if (unlikely(err < 0)) {
1674 kfree_skb(skb);
1675 return ERR_PTR(err);
1676 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001677
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001678 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001679 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001680
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001681 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001682 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683}
1684
Szymon Janc67c9e842011-07-28 16:24:33 +02001685static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001686{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001687 struct sk_buff *skb;
1688 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001689 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001690 size_t size = 0;
1691
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001692 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001693 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001694 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001695 if (IS_ERR(skb))
1696 return PTR_ERR(skb);
1697
1698 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001699 len -= chan->remote_mps;
1700 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001701
1702 while (len > 0) {
1703 size_t buflen;
1704
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001705 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001706 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001707 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001708 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001709 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001710 buflen = len;
1711 }
1712
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001713 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001714 if (IS_ERR(skb)) {
1715 skb_queue_purge(&sar_queue);
1716 return PTR_ERR(skb);
1717 }
1718
1719 __skb_queue_tail(&sar_queue, skb);
1720 len -= buflen;
1721 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001722 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001723 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1724 if (chan->tx_send_head == NULL)
1725 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001726
1727 return size;
1728}
1729
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001730int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1731 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001732{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001733 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001734 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001735 int err;
1736
1737 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001738 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001739 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001740 if (IS_ERR(skb))
1741 return PTR_ERR(skb);
1742
1743 l2cap_do_send(chan, skb);
1744 return len;
1745 }
1746
1747 switch (chan->mode) {
1748 case L2CAP_MODE_BASIC:
1749 /* Check outgoing MTU */
1750 if (len > chan->omtu)
1751 return -EMSGSIZE;
1752
1753 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001754 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001755 if (IS_ERR(skb))
1756 return PTR_ERR(skb);
1757
1758 l2cap_do_send(chan, skb);
1759 err = len;
1760 break;
1761
1762 case L2CAP_MODE_ERTM:
1763 case L2CAP_MODE_STREAMING:
1764 /* Entire SDU fits into one PDU */
1765 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001766 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001767 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1768 0);
1769 if (IS_ERR(skb))
1770 return PTR_ERR(skb);
1771
1772 __skb_queue_tail(&chan->tx_q, skb);
1773
1774 if (chan->tx_send_head == NULL)
1775 chan->tx_send_head = skb;
1776
1777 } else {
1778 /* Segment SDU into multiples PDUs */
1779 err = l2cap_sar_segment_sdu(chan, msg, len);
1780 if (err < 0)
1781 return err;
1782 }
1783
1784 if (chan->mode == L2CAP_MODE_STREAMING) {
1785 l2cap_streaming_send(chan);
1786 err = len;
1787 break;
1788 }
1789
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001790 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1791 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001792 err = len;
1793 break;
1794 }
1795
1796 err = l2cap_ertm_send(chan);
1797 if (err >= 0)
1798 err = len;
1799
1800 break;
1801
1802 default:
1803 BT_DBG("bad state %1.1x", chan->mode);
1804 err = -EBADFD;
1805 }
1806
1807 return err;
1808}
1809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810/* Copy frame to all raw sockets on that connection */
1811static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1812{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001814 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815
1816 BT_DBG("conn %p", conn);
1817
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001818 rcu_read_lock();
1819
1820 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001821 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001822 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 continue;
1824
1825 /* Don't send frame to the socket it came from */
1826 if (skb->sk == sk)
1827 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001828 nskb = skb_clone(skb, GFP_ATOMIC);
1829 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 continue;
1831
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001832 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 kfree_skb(nskb);
1834 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001835
1836 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837}
1838
1839/* ---- L2CAP signalling commands ---- */
1840static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1841 u8 code, u8 ident, u16 dlen, void *data)
1842{
1843 struct sk_buff *skb, **frag;
1844 struct l2cap_cmd_hdr *cmd;
1845 struct l2cap_hdr *lh;
1846 int len, count;
1847
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001848 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1849 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1852 count = min_t(unsigned int, conn->mtu, len);
1853
1854 skb = bt_skb_alloc(count, GFP_ATOMIC);
1855 if (!skb)
1856 return NULL;
1857
1858 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001859 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001860
1861 if (conn->hcon->type == LE_LINK)
1862 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1863 else
1864 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
1866 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1867 cmd->code = code;
1868 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001869 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870
1871 if (dlen) {
1872 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1873 memcpy(skb_put(skb, count), data, count);
1874 data += count;
1875 }
1876
1877 len -= skb->len;
1878
1879 /* Continuation fragments (no L2CAP header) */
1880 frag = &skb_shinfo(skb)->frag_list;
1881 while (len) {
1882 count = min_t(unsigned int, conn->mtu, len);
1883
1884 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1885 if (!*frag)
1886 goto fail;
1887
1888 memcpy(skb_put(*frag, count), data, count);
1889
1890 len -= count;
1891 data += count;
1892
1893 frag = &(*frag)->next;
1894 }
1895
1896 return skb;
1897
1898fail:
1899 kfree_skb(skb);
1900 return NULL;
1901}
1902
1903static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1904{
1905 struct l2cap_conf_opt *opt = *ptr;
1906 int len;
1907
1908 len = L2CAP_CONF_OPT_SIZE + opt->len;
1909 *ptr += len;
1910
1911 *type = opt->type;
1912 *olen = opt->len;
1913
1914 switch (opt->len) {
1915 case 1:
1916 *val = *((u8 *) opt->val);
1917 break;
1918
1919 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001920 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921 break;
1922
1923 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001924 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 break;
1926
1927 default:
1928 *val = (unsigned long) opt->val;
1929 break;
1930 }
1931
1932 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1933 return len;
1934}
1935
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1937{
1938 struct l2cap_conf_opt *opt = *ptr;
1939
1940 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1941
1942 opt->type = type;
1943 opt->len = len;
1944
1945 switch (len) {
1946 case 1:
1947 *((u8 *) opt->val) = val;
1948 break;
1949
1950 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001951 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 break;
1953
1954 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001955 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 break;
1957
1958 default:
1959 memcpy(opt->val, (void *) val, len);
1960 break;
1961 }
1962
1963 *ptr += L2CAP_CONF_OPT_SIZE + len;
1964}
1965
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001966static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1967{
1968 struct l2cap_conf_efs efs;
1969
Szymon Janc1ec918c2011-11-16 09:32:21 +01001970 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001971 case L2CAP_MODE_ERTM:
1972 efs.id = chan->local_id;
1973 efs.stype = chan->local_stype;
1974 efs.msdu = cpu_to_le16(chan->local_msdu);
1975 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1976 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1977 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1978 break;
1979
1980 case L2CAP_MODE_STREAMING:
1981 efs.id = 1;
1982 efs.stype = L2CAP_SERV_BESTEFFORT;
1983 efs.msdu = cpu_to_le16(chan->local_msdu);
1984 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1985 efs.acc_lat = 0;
1986 efs.flush_to = 0;
1987 break;
1988
1989 default:
1990 return;
1991 }
1992
1993 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
1994 (unsigned long) &efs);
1995}
1996
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001997static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001998{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001999 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2000 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002001
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02002002 BT_DBG("chan %p", chan);
2003
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002004 lock_sock(chan->sk);
Szymon Jancb17e73b2012-01-11 10:59:47 +01002005 __l2cap_send_ack(chan);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002006 release_sock(chan->sk);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002007
2008 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002009}
2010
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002011static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002012{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002013 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002014 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002015 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002016 chan->num_acked = 0;
2017 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002018
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002019 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2020 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2021 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002022
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002023 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002024
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002025 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002026}
2027
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002028static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2029{
2030 switch (mode) {
2031 case L2CAP_MODE_STREAMING:
2032 case L2CAP_MODE_ERTM:
2033 if (l2cap_mode_supported(mode, remote_feat_mask))
2034 return mode;
2035 /* fall through */
2036 default:
2037 return L2CAP_MODE_BASIC;
2038 }
2039}
2040
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002041static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2042{
2043 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2044}
2045
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002046static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2047{
2048 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2049}
2050
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002051static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2052{
2053 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002054 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002055 /* use extended control field */
2056 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002057 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2058 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002059 chan->tx_win = min_t(u16, chan->tx_win,
2060 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002061 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2062 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002063}
2064
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002065static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002068 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002070 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002072 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002074 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002075 goto done;
2076
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002077 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002078 case L2CAP_MODE_STREAMING:
2079 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002080 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002081 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002082
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002083 if (__l2cap_efs_supported(chan))
2084 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2085
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002086 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002087 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002088 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002089 break;
2090 }
2091
2092done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002093 if (chan->imtu != L2CAP_DEFAULT_MTU)
2094 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002095
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002096 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002097 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002098 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2099 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002100 break;
2101
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002102 rfc.mode = L2CAP_MODE_BASIC;
2103 rfc.txwin_size = 0;
2104 rfc.max_transmit = 0;
2105 rfc.retrans_timeout = 0;
2106 rfc.monitor_timeout = 0;
2107 rfc.max_pdu_size = 0;
2108
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002109 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2110 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002111 break;
2112
2113 case L2CAP_MODE_ERTM:
2114 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002115 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002116 rfc.retrans_timeout = 0;
2117 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002118
2119 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2120 L2CAP_EXT_HDR_SIZE -
2121 L2CAP_SDULEN_SIZE -
2122 L2CAP_FCS_SIZE);
2123 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002124
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002125 l2cap_txwin_setup(chan);
2126
2127 rfc.txwin_size = min_t(u16, chan->tx_win,
2128 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002129
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002130 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2131 (unsigned long) &rfc);
2132
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002133 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2134 l2cap_add_opt_efs(&ptr, chan);
2135
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002136 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002137 break;
2138
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002139 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002140 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002141 chan->fcs = L2CAP_FCS_NONE;
2142 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002143 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002144
2145 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2146 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2147 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002148 break;
2149
2150 case L2CAP_MODE_STREAMING:
2151 rfc.mode = L2CAP_MODE_STREAMING;
2152 rfc.txwin_size = 0;
2153 rfc.max_transmit = 0;
2154 rfc.retrans_timeout = 0;
2155 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002156
2157 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2158 L2CAP_EXT_HDR_SIZE -
2159 L2CAP_SDULEN_SIZE -
2160 L2CAP_FCS_SIZE);
2161 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002162
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002163 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2164 (unsigned long) &rfc);
2165
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002166 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2167 l2cap_add_opt_efs(&ptr, chan);
2168
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002169 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002170 break;
2171
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002172 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002173 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002174 chan->fcs = L2CAP_FCS_NONE;
2175 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002176 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002177 break;
2178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002180 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002181 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182
2183 return ptr - data;
2184}
2185
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002186static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002188 struct l2cap_conf_rsp *rsp = data;
2189 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002190 void *req = chan->conf_req;
2191 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002192 int type, hint, olen;
2193 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002194 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002195 struct l2cap_conf_efs efs;
2196 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002197 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002198 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002199 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002201 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002202
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002203 while (len >= L2CAP_CONF_OPT_SIZE) {
2204 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002206 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002207 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002208
2209 switch (type) {
2210 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002211 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002212 break;
2213
2214 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002215 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002216 break;
2217
2218 case L2CAP_CONF_QOS:
2219 break;
2220
Marcel Holtmann6464f352007-10-20 13:39:51 +02002221 case L2CAP_CONF_RFC:
2222 if (olen == sizeof(rfc))
2223 memcpy(&rfc, (void *) val, olen);
2224 break;
2225
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002226 case L2CAP_CONF_FCS:
2227 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002228 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002229 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002230
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002231 case L2CAP_CONF_EFS:
2232 remote_efs = 1;
2233 if (olen == sizeof(efs))
2234 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002235 break;
2236
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002237 case L2CAP_CONF_EWS:
2238 if (!enable_hs)
2239 return -ECONNREFUSED;
2240
2241 set_bit(FLAG_EXT_CTRL, &chan->flags);
2242 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002243 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002244 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002245 break;
2246
2247 default:
2248 if (hint)
2249 break;
2250
2251 result = L2CAP_CONF_UNKNOWN;
2252 *((u8 *) ptr++) = type;
2253 break;
2254 }
2255 }
2256
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002257 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002258 goto done;
2259
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002260 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002261 case L2CAP_MODE_STREAMING:
2262 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002263 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002264 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002265 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002266 break;
2267 }
2268
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002269 if (remote_efs) {
2270 if (__l2cap_efs_supported(chan))
2271 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2272 else
2273 return -ECONNREFUSED;
2274 }
2275
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002276 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002277 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002278
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002279 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002280 }
2281
2282done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002283 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002284 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002285 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002286
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002287 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002288 return -ECONNREFUSED;
2289
2290 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2291 sizeof(rfc), (unsigned long) &rfc);
2292 }
2293
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002294 if (result == L2CAP_CONF_SUCCESS) {
2295 /* Configure output options and let the other side know
2296 * which ones we don't like. */
2297
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002298 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2299 result = L2CAP_CONF_UNACCEPT;
2300 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002301 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002302 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002303 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002304 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002305
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002306 if (remote_efs) {
2307 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2308 efs.stype != L2CAP_SERV_NOTRAFIC &&
2309 efs.stype != chan->local_stype) {
2310
2311 result = L2CAP_CONF_UNACCEPT;
2312
2313 if (chan->num_conf_req >= 1)
2314 return -ECONNREFUSED;
2315
2316 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002317 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002318 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002319 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002320 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002321 result = L2CAP_CONF_PENDING;
2322 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002323 }
2324 }
2325
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002326 switch (rfc.mode) {
2327 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002328 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002329 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002330 break;
2331
2332 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002333 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2334 chan->remote_tx_win = rfc.txwin_size;
2335 else
2336 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2337
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002338 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002339
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002340 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2341 chan->conn->mtu -
2342 L2CAP_EXT_HDR_SIZE -
2343 L2CAP_SDULEN_SIZE -
2344 L2CAP_FCS_SIZE);
2345 rfc.max_pdu_size = cpu_to_le16(size);
2346 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002347
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002348 rfc.retrans_timeout =
2349 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2350 rfc.monitor_timeout =
2351 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002352
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002353 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002354
2355 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2356 sizeof(rfc), (unsigned long) &rfc);
2357
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002358 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2359 chan->remote_id = efs.id;
2360 chan->remote_stype = efs.stype;
2361 chan->remote_msdu = le16_to_cpu(efs.msdu);
2362 chan->remote_flush_to =
2363 le32_to_cpu(efs.flush_to);
2364 chan->remote_acc_lat =
2365 le32_to_cpu(efs.acc_lat);
2366 chan->remote_sdu_itime =
2367 le32_to_cpu(efs.sdu_itime);
2368 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2369 sizeof(efs), (unsigned long) &efs);
2370 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002371 break;
2372
2373 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002374 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2375 chan->conn->mtu -
2376 L2CAP_EXT_HDR_SIZE -
2377 L2CAP_SDULEN_SIZE -
2378 L2CAP_FCS_SIZE);
2379 rfc.max_pdu_size = cpu_to_le16(size);
2380 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002381
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002382 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002383
2384 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2385 sizeof(rfc), (unsigned long) &rfc);
2386
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002387 break;
2388
2389 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002390 result = L2CAP_CONF_UNACCEPT;
2391
2392 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002393 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002394 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002395
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002396 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002397 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002398 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002399 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002400 rsp->result = cpu_to_le16(result);
2401 rsp->flags = cpu_to_le16(0x0000);
2402
2403 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404}
2405
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002406static 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 -03002407{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002408 struct l2cap_conf_req *req = data;
2409 void *ptr = req->data;
2410 int type, olen;
2411 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002412 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002413 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002414
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002415 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002416
2417 while (len >= L2CAP_CONF_OPT_SIZE) {
2418 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2419
2420 switch (type) {
2421 case L2CAP_CONF_MTU:
2422 if (val < L2CAP_DEFAULT_MIN_MTU) {
2423 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002424 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002425 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002426 chan->imtu = val;
2427 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002428 break;
2429
2430 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002431 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002432 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002433 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002434 break;
2435
2436 case L2CAP_CONF_RFC:
2437 if (olen == sizeof(rfc))
2438 memcpy(&rfc, (void *)val, olen);
2439
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002440 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002441 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002442 return -ECONNREFUSED;
2443
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002444 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002445
2446 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2447 sizeof(rfc), (unsigned long) &rfc);
2448 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002449
2450 case L2CAP_CONF_EWS:
2451 chan->tx_win = min_t(u16, val,
2452 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002453 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2454 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002455 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002456
2457 case L2CAP_CONF_EFS:
2458 if (olen == sizeof(efs))
2459 memcpy(&efs, (void *)val, olen);
2460
2461 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2462 efs.stype != L2CAP_SERV_NOTRAFIC &&
2463 efs.stype != chan->local_stype)
2464 return -ECONNREFUSED;
2465
2466 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2467 sizeof(efs), (unsigned long) &efs);
2468 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002469 }
2470 }
2471
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002472 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002473 return -ECONNREFUSED;
2474
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002475 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002476
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002477 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002478 switch (rfc.mode) {
2479 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002480 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2481 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2482 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002483
2484 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2485 chan->local_msdu = le16_to_cpu(efs.msdu);
2486 chan->local_sdu_itime =
2487 le32_to_cpu(efs.sdu_itime);
2488 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2489 chan->local_flush_to =
2490 le32_to_cpu(efs.flush_to);
2491 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002492 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002493
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002494 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002495 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002496 }
2497 }
2498
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002499 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002500 req->flags = cpu_to_le16(0x0000);
2501
2502 return ptr - data;
2503}
2504
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002505static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506{
2507 struct l2cap_conf_rsp *rsp = data;
2508 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002510 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002512 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002513 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002514 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
2516 return ptr - data;
2517}
2518
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002519void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002520{
2521 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002522 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002523 u8 buf[128];
2524
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002525 rsp.scid = cpu_to_le16(chan->dcid);
2526 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002527 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2528 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2529 l2cap_send_cmd(conn, chan->ident,
2530 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2531
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002532 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002533 return;
2534
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002535 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2536 l2cap_build_conf_req(chan, buf), buf);
2537 chan->num_conf_req++;
2538}
2539
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002540static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002541{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002542 int type, olen;
2543 unsigned long val;
2544 struct l2cap_conf_rfc rfc;
2545
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002546 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002547
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002548 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002549 return;
2550
2551 while (len >= L2CAP_CONF_OPT_SIZE) {
2552 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2553
2554 switch (type) {
2555 case L2CAP_CONF_RFC:
2556 if (olen == sizeof(rfc))
2557 memcpy(&rfc, (void *)val, olen);
2558 goto done;
2559 }
2560 }
2561
Mat Martineau36e999a2011-12-08 17:23:21 -08002562 /* Use sane default values in case a misbehaving remote device
2563 * did not send an RFC option.
2564 */
2565 rfc.mode = chan->mode;
2566 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2567 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2568 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2569
2570 BT_ERR("Expected RFC option was not found, using defaults");
2571
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002572done:
2573 switch (rfc.mode) {
2574 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002575 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2576 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2577 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002578 break;
2579 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002580 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002581 }
2582}
2583
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002584static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2585{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002586 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002587
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002588 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002589 return 0;
2590
2591 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2592 cmd->ident == conn->info_ident) {
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02002593 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002594
2595 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002596 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002597
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002598 l2cap_conn_start(conn);
2599 }
2600
2601 return 0;
2602}
2603
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2605{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2607 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002608 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002609 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002610 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
2612 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002613 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2616
2617 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002618 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2619 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620 result = L2CAP_CR_BAD_PSM;
2621 goto sendresp;
2622 }
2623
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002624 parent = pchan->sk;
2625
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002626 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002627
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002628 /* Check if the ACL is secure enough (if not SDP) */
2629 if (psm != cpu_to_le16(0x0001) &&
2630 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002631 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002632 result = L2CAP_CR_SEC_BLOCK;
2633 goto response;
2634 }
2635
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 result = L2CAP_CR_NO_MEM;
2637
2638 /* Check for backlog size */
2639 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002640 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 goto response;
2642 }
2643
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002644 chan = pchan->ops->new_connection(pchan->data);
2645 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 goto response;
2647
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002648 sk = chan->sk;
2649
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002651 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002653 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 goto response;
2655 }
2656
2657 hci_conn_hold(conn->hcon);
2658
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 bacpy(&bt_sk(sk)->src, conn->src);
2660 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002661 chan->psm = psm;
2662 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002664 bt_accept_enqueue(parent, sk);
2665
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02002666 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002667
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002668 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002670 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002672 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
Marcel Holtmann984947d2009-02-06 23:35:19 +01002674 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002675 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002676 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002677 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002678 result = L2CAP_CR_PEND;
2679 status = L2CAP_CS_AUTHOR_PEND;
2680 parent->sk_data_ready(parent, 0);
2681 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002682 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002683 result = L2CAP_CR_SUCCESS;
2684 status = L2CAP_CS_NO_INFO;
2685 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002686 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002687 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002688 result = L2CAP_CR_PEND;
2689 status = L2CAP_CS_AUTHEN_PEND;
2690 }
2691 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002692 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002693 result = L2CAP_CR_PEND;
2694 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 }
2696
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002698 release_sock(parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699
2700sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002701 rsp.scid = cpu_to_le16(scid);
2702 rsp.dcid = cpu_to_le16(dcid);
2703 rsp.result = cpu_to_le16(result);
2704 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002706
2707 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2708 struct l2cap_info_req info;
2709 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2710
2711 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2712 conn->info_ident = l2cap_get_ident(conn);
2713
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02002714 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002715 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2716
2717 l2cap_send_cmd(conn, conn->info_ident,
2718 L2CAP_INFO_REQ, sizeof(info), &info);
2719 }
2720
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002721 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002722 result == L2CAP_CR_SUCCESS) {
2723 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002724 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002725 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002726 l2cap_build_conf_req(chan, buf), buf);
2727 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002728 }
2729
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 return 0;
2731}
2732
2733static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2734{
2735 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2736 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002737 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 struct sock *sk;
2739 u8 req[128];
2740
2741 scid = __le16_to_cpu(rsp->scid);
2742 dcid = __le16_to_cpu(rsp->dcid);
2743 result = __le16_to_cpu(rsp->result);
2744 status = __le16_to_cpu(rsp->status);
2745
2746 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2747
2748 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002749 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002750 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002751 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002753 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002754 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002755 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 }
2757
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002758 sk = chan->sk;
2759
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 switch (result) {
2761 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002762 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002763 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002764 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002765 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002766
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002767 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002768 break;
2769
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002771 l2cap_build_conf_req(chan, req), req);
2772 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 break;
2774
2775 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002776 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 break;
2778
2779 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002780 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 break;
2782 }
2783
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002784 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785 return 0;
2786}
2787
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002788static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002789{
2790 /* FCS is enabled only in ERTM or streaming mode, if one or both
2791 * sides request it.
2792 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002793 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002794 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002795 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002796 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002797}
2798
Al Viro88219a02007-07-29 00:17:25 -07002799static 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 -07002800{
2801 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2802 u16 dcid, flags;
2803 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002804 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002806 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807
2808 dcid = __le16_to_cpu(req->dcid);
2809 flags = __le16_to_cpu(req->flags);
2810
2811 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2812
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002813 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002814 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815 return -ENOENT;
2816
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002817 sk = chan->sk;
2818
David S. Miller033b1142011-07-21 13:38:42 -07002819 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002820 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002821
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002822 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2823 rej.scid = cpu_to_le16(chan->scid);
2824 rej.dcid = cpu_to_le16(chan->dcid);
2825
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002826 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2827 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002828 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002829 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002830
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002831 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002832 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002833 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002834 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002835 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002836 L2CAP_CONF_REJECT, flags), rsp);
2837 goto unlock;
2838 }
2839
2840 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002841 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2842 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843
2844 if (flags & 0x0001) {
2845 /* Incomplete config. Send empty response. */
2846 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002847 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002848 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 goto unlock;
2850 }
2851
2852 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002853 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002854 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002855 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002857 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002859 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002860 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002861
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002862 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002863 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002864
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002865 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002866 goto unlock;
2867
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002868 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002869 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002870
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002871 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002872
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002873 chan->next_tx_seq = 0;
2874 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002875 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002876 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002877 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002878
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02002879 l2cap_chan_ready(chan);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002880 goto unlock;
2881 }
2882
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002883 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002884 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002886 l2cap_build_conf_req(chan, buf), buf);
2887 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 }
2889
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002890 /* Got Conf Rsp PENDING from remote side and asume we sent
2891 Conf Rsp PENDING in the code above */
2892 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2893 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2894
2895 /* check compatibility */
2896
2897 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2898 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2899
2900 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002901 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002902 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2903 }
2904
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905unlock:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002906 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 return 0;
2908}
2909
2910static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2911{
2912 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2913 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002914 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002915 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002916 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
2918 scid = __le16_to_cpu(rsp->scid);
2919 flags = __le16_to_cpu(rsp->flags);
2920 result = __le16_to_cpu(rsp->result);
2921
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002922 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2923 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002925 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002926 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 return 0;
2928
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002929 sk = chan->sk;
2930
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 switch (result) {
2932 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002933 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002934 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002935 break;
2936
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002937 case L2CAP_CONF_PENDING:
2938 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2939
2940 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2941 char buf[64];
2942
2943 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2944 buf, &result);
2945 if (len < 0) {
2946 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2947 goto done;
2948 }
2949
2950 /* check compatibility */
2951
2952 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2953 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2954
2955 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002956 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002957 L2CAP_CONF_SUCCESS, 0x0000), buf);
2958 }
2959 goto done;
2960
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002962 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002963 char req[64];
2964
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002965 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002966 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002967 goto done;
2968 }
2969
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002970 /* throw out any old stored conf requests */
2971 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002972 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2973 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002974 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002975 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002976 goto done;
2977 }
2978
2979 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2980 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002981 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002982 if (result != L2CAP_CONF_SUCCESS)
2983 goto done;
2984 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 }
2986
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002987 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002988 sk->sk_err = ECONNRESET;
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01002989 __set_chan_timer(chan,
2990 msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT));
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002991 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 goto done;
2993 }
2994
2995 if (flags & 0x01)
2996 goto done;
2997
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002998 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03003000 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003001 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003002
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003003 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003004 chan->next_tx_seq = 0;
3005 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003006 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003007 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003008 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003009
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02003010 l2cap_chan_ready(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 }
3012
3013done:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003014 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 return 0;
3016}
3017
3018static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3019{
3020 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3021 struct l2cap_disconn_rsp rsp;
3022 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003023 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 struct sock *sk;
3025
3026 scid = __le16_to_cpu(req->scid);
3027 dcid = __le16_to_cpu(req->dcid);
3028
3029 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3030
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003031 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003032 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 return 0;
3034
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003035 sk = chan->sk;
3036
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003037 rsp.dcid = cpu_to_le16(chan->scid);
3038 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3040
3041 sk->sk_shutdown = SHUTDOWN_MASK;
3042
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003043 l2cap_chan_del(chan, ECONNRESET);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003044 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003046 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 return 0;
3048}
3049
3050static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3051{
3052 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3053 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003054 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055 struct sock *sk;
3056
3057 scid = __le16_to_cpu(rsp->scid);
3058 dcid = __le16_to_cpu(rsp->dcid);
3059
3060 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3061
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003062 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003063 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 return 0;
3065
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003066 sk = chan->sk;
3067
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003068 l2cap_chan_del(chan, 0);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003069 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003071 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 return 0;
3073}
3074
3075static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3076{
3077 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078 u16 type;
3079
3080 type = __le16_to_cpu(req->type);
3081
3082 BT_DBG("type 0x%4.4x", type);
3083
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003084 if (type == L2CAP_IT_FEAT_MASK) {
3085 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003086 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003087 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3088 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3089 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003090 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003091 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3092 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003093 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003094 feat_mask |= L2CAP_FEAT_EXT_FLOW
3095 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003096
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003097 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003098 l2cap_send_cmd(conn, cmd->ident,
3099 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003100 } else if (type == L2CAP_IT_FIXED_CHAN) {
3101 u8 buf[12];
3102 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003103
3104 if (enable_hs)
3105 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3106 else
3107 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3108
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003109 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3110 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003111 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003112 l2cap_send_cmd(conn, cmd->ident,
3113 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003114 } else {
3115 struct l2cap_info_rsp rsp;
3116 rsp.type = cpu_to_le16(type);
3117 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3118 l2cap_send_cmd(conn, cmd->ident,
3119 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3120 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003121
3122 return 0;
3123}
3124
3125static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3126{
3127 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3128 u16 type, result;
3129
3130 type = __le16_to_cpu(rsp->type);
3131 result = __le16_to_cpu(rsp->result);
3132
3133 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3134
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003135 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3136 if (cmd->ident != conn->info_ident ||
3137 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3138 return 0;
3139
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02003140 cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003141
Ville Tervoadb08ed2010-08-04 09:43:33 +03003142 if (result != L2CAP_IR_SUCCESS) {
3143 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3144 conn->info_ident = 0;
3145
3146 l2cap_conn_start(conn);
3147
3148 return 0;
3149 }
3150
Marcel Holtmann984947d2009-02-06 23:35:19 +01003151 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003152 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003153
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003154 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003155 struct l2cap_info_req req;
3156 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3157
3158 conn->info_ident = l2cap_get_ident(conn);
3159
3160 l2cap_send_cmd(conn, conn->info_ident,
3161 L2CAP_INFO_REQ, sizeof(req), &req);
3162 } else {
3163 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3164 conn->info_ident = 0;
3165
3166 l2cap_conn_start(conn);
3167 }
3168 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003169 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003170 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003171
3172 l2cap_conn_start(conn);
3173 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003174
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 return 0;
3176}
3177
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003178static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3179 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3180 void *data)
3181{
3182 struct l2cap_create_chan_req *req = data;
3183 struct l2cap_create_chan_rsp rsp;
3184 u16 psm, scid;
3185
3186 if (cmd_len != sizeof(*req))
3187 return -EPROTO;
3188
3189 if (!enable_hs)
3190 return -EINVAL;
3191
3192 psm = le16_to_cpu(req->psm);
3193 scid = le16_to_cpu(req->scid);
3194
3195 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3196
3197 /* Placeholder: Always reject */
3198 rsp.dcid = 0;
3199 rsp.scid = cpu_to_le16(scid);
3200 rsp.result = L2CAP_CR_NO_MEM;
3201 rsp.status = L2CAP_CS_NO_INFO;
3202
3203 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3204 sizeof(rsp), &rsp);
3205
3206 return 0;
3207}
3208
3209static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3210 struct l2cap_cmd_hdr *cmd, void *data)
3211{
3212 BT_DBG("conn %p", conn);
3213
3214 return l2cap_connect_rsp(conn, cmd, data);
3215}
3216
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003217static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3218 u16 icid, u16 result)
3219{
3220 struct l2cap_move_chan_rsp rsp;
3221
3222 BT_DBG("icid %d, result %d", icid, result);
3223
3224 rsp.icid = cpu_to_le16(icid);
3225 rsp.result = cpu_to_le16(result);
3226
3227 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3228}
3229
3230static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3231 struct l2cap_chan *chan, u16 icid, u16 result)
3232{
3233 struct l2cap_move_chan_cfm cfm;
3234 u8 ident;
3235
3236 BT_DBG("icid %d, result %d", icid, result);
3237
3238 ident = l2cap_get_ident(conn);
3239 if (chan)
3240 chan->ident = ident;
3241
3242 cfm.icid = cpu_to_le16(icid);
3243 cfm.result = cpu_to_le16(result);
3244
3245 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3246}
3247
3248static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3249 u16 icid)
3250{
3251 struct l2cap_move_chan_cfm_rsp rsp;
3252
3253 BT_DBG("icid %d", icid);
3254
3255 rsp.icid = cpu_to_le16(icid);
3256 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3257}
3258
3259static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3260 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3261{
3262 struct l2cap_move_chan_req *req = data;
3263 u16 icid = 0;
3264 u16 result = L2CAP_MR_NOT_ALLOWED;
3265
3266 if (cmd_len != sizeof(*req))
3267 return -EPROTO;
3268
3269 icid = le16_to_cpu(req->icid);
3270
3271 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3272
3273 if (!enable_hs)
3274 return -EINVAL;
3275
3276 /* Placeholder: Always refuse */
3277 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3278
3279 return 0;
3280}
3281
3282static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3283 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3284{
3285 struct l2cap_move_chan_rsp *rsp = data;
3286 u16 icid, result;
3287
3288 if (cmd_len != sizeof(*rsp))
3289 return -EPROTO;
3290
3291 icid = le16_to_cpu(rsp->icid);
3292 result = le16_to_cpu(rsp->result);
3293
3294 BT_DBG("icid %d, result %d", icid, result);
3295
3296 /* Placeholder: Always unconfirmed */
3297 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3298
3299 return 0;
3300}
3301
3302static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3303 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3304{
3305 struct l2cap_move_chan_cfm *cfm = data;
3306 u16 icid, result;
3307
3308 if (cmd_len != sizeof(*cfm))
3309 return -EPROTO;
3310
3311 icid = le16_to_cpu(cfm->icid);
3312 result = le16_to_cpu(cfm->result);
3313
3314 BT_DBG("icid %d, result %d", icid, result);
3315
3316 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3317
3318 return 0;
3319}
3320
3321static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3322 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3323{
3324 struct l2cap_move_chan_cfm_rsp *rsp = data;
3325 u16 icid;
3326
3327 if (cmd_len != sizeof(*rsp))
3328 return -EPROTO;
3329
3330 icid = le16_to_cpu(rsp->icid);
3331
3332 BT_DBG("icid %d", icid);
3333
3334 return 0;
3335}
3336
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003337static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003338 u16 to_multiplier)
3339{
3340 u16 max_latency;
3341
3342 if (min > max || min < 6 || max > 3200)
3343 return -EINVAL;
3344
3345 if (to_multiplier < 10 || to_multiplier > 3200)
3346 return -EINVAL;
3347
3348 if (max >= to_multiplier * 8)
3349 return -EINVAL;
3350
3351 max_latency = (to_multiplier * 8 / max) - 1;
3352 if (latency > 499 || latency > max_latency)
3353 return -EINVAL;
3354
3355 return 0;
3356}
3357
3358static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3359 struct l2cap_cmd_hdr *cmd, u8 *data)
3360{
3361 struct hci_conn *hcon = conn->hcon;
3362 struct l2cap_conn_param_update_req *req;
3363 struct l2cap_conn_param_update_rsp rsp;
3364 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003365 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003366
3367 if (!(hcon->link_mode & HCI_LM_MASTER))
3368 return -EINVAL;
3369
3370 cmd_len = __le16_to_cpu(cmd->len);
3371 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3372 return -EPROTO;
3373
3374 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003375 min = __le16_to_cpu(req->min);
3376 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003377 latency = __le16_to_cpu(req->latency);
3378 to_multiplier = __le16_to_cpu(req->to_multiplier);
3379
3380 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3381 min, max, latency, to_multiplier);
3382
3383 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003384
3385 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3386 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003387 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3388 else
3389 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3390
3391 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3392 sizeof(rsp), &rsp);
3393
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003394 if (!err)
3395 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3396
Claudio Takahaside731152011-02-11 19:28:55 -02003397 return 0;
3398}
3399
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003400static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3401 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3402{
3403 int err = 0;
3404
3405 switch (cmd->code) {
3406 case L2CAP_COMMAND_REJ:
3407 l2cap_command_rej(conn, cmd, data);
3408 break;
3409
3410 case L2CAP_CONN_REQ:
3411 err = l2cap_connect_req(conn, cmd, data);
3412 break;
3413
3414 case L2CAP_CONN_RSP:
3415 err = l2cap_connect_rsp(conn, cmd, data);
3416 break;
3417
3418 case L2CAP_CONF_REQ:
3419 err = l2cap_config_req(conn, cmd, cmd_len, data);
3420 break;
3421
3422 case L2CAP_CONF_RSP:
3423 err = l2cap_config_rsp(conn, cmd, data);
3424 break;
3425
3426 case L2CAP_DISCONN_REQ:
3427 err = l2cap_disconnect_req(conn, cmd, data);
3428 break;
3429
3430 case L2CAP_DISCONN_RSP:
3431 err = l2cap_disconnect_rsp(conn, cmd, data);
3432 break;
3433
3434 case L2CAP_ECHO_REQ:
3435 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3436 break;
3437
3438 case L2CAP_ECHO_RSP:
3439 break;
3440
3441 case L2CAP_INFO_REQ:
3442 err = l2cap_information_req(conn, cmd, data);
3443 break;
3444
3445 case L2CAP_INFO_RSP:
3446 err = l2cap_information_rsp(conn, cmd, data);
3447 break;
3448
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003449 case L2CAP_CREATE_CHAN_REQ:
3450 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3451 break;
3452
3453 case L2CAP_CREATE_CHAN_RSP:
3454 err = l2cap_create_channel_rsp(conn, cmd, data);
3455 break;
3456
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003457 case L2CAP_MOVE_CHAN_REQ:
3458 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3459 break;
3460
3461 case L2CAP_MOVE_CHAN_RSP:
3462 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3463 break;
3464
3465 case L2CAP_MOVE_CHAN_CFM:
3466 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3467 break;
3468
3469 case L2CAP_MOVE_CHAN_CFM_RSP:
3470 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3471 break;
3472
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003473 default:
3474 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3475 err = -EINVAL;
3476 break;
3477 }
3478
3479 return err;
3480}
3481
3482static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3483 struct l2cap_cmd_hdr *cmd, u8 *data)
3484{
3485 switch (cmd->code) {
3486 case L2CAP_COMMAND_REJ:
3487 return 0;
3488
3489 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003490 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003491
3492 case L2CAP_CONN_PARAM_UPDATE_RSP:
3493 return 0;
3494
3495 default:
3496 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3497 return -EINVAL;
3498 }
3499}
3500
3501static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3502 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503{
3504 u8 *data = skb->data;
3505 int len = skb->len;
3506 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003507 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508
3509 l2cap_raw_recv(conn, skb);
3510
3511 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003512 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3514 data += L2CAP_CMD_HDR_SIZE;
3515 len -= L2CAP_CMD_HDR_SIZE;
3516
Al Viro88219a02007-07-29 00:17:25 -07003517 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
Al Viro88219a02007-07-29 00:17:25 -07003519 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 -07003520
Al Viro88219a02007-07-29 00:17:25 -07003521 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 BT_DBG("corrupted command");
3523 break;
3524 }
3525
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003526 if (conn->hcon->type == LE_LINK)
3527 err = l2cap_le_sig_cmd(conn, &cmd, data);
3528 else
3529 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530
3531 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003532 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003533
3534 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535
3536 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003537 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3539 }
3540
Al Viro88219a02007-07-29 00:17:25 -07003541 data += cmd_len;
3542 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003543 }
3544
3545 kfree_skb(skb);
3546}
3547
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003548static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003549{
3550 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003551 int hdr_size;
3552
3553 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3554 hdr_size = L2CAP_EXT_HDR_SIZE;
3555 else
3556 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003557
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003558 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003559 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003560 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3561 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3562
3563 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003564 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003565 }
3566 return 0;
3567}
3568
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003569static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003570{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003571 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003572
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003573 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003574
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003575 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003576
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003577 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003578 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003579 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003580 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003581 }
3582
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003583 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003584 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003585
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003586 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003587
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003588 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003589 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003590 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003591 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003592 }
3593}
3594
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003595static 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 -03003596{
3597 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003598 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003599
3600 bt_cb(skb)->tx_seq = tx_seq;
3601 bt_cb(skb)->sar = sar;
3602
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003603 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003604
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003605 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003606
Szymon Janc039d9572011-11-16 09:32:19 +01003607 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003608 if (bt_cb(next_skb)->tx_seq == tx_seq)
3609 return -EINVAL;
3610
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003611 next_tx_seq_offset = __seq_offset(chan,
3612 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003613
3614 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003615 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003616 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003617 }
3618
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003619 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003620 next_skb = NULL;
3621 else
3622 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3623 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003624
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003625 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003626
3627 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003628}
3629
Mat Martineau84084a32011-07-22 14:54:00 -07003630static void append_skb_frag(struct sk_buff *skb,
3631 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003632{
Mat Martineau84084a32011-07-22 14:54:00 -07003633 /* skb->len reflects data in skb as well as all fragments
3634 * skb->data_len reflects only data in fragments
3635 */
3636 if (!skb_has_frag_list(skb))
3637 skb_shinfo(skb)->frag_list = new_frag;
3638
3639 new_frag->next = NULL;
3640
3641 (*last_frag)->next = new_frag;
3642 *last_frag = new_frag;
3643
3644 skb->len += new_frag->len;
3645 skb->data_len += new_frag->len;
3646 skb->truesize += new_frag->truesize;
3647}
3648
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003649static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003650{
3651 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003652
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003653 switch (__get_ctrl_sar(chan, control)) {
3654 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003655 if (chan->sdu)
3656 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003657
Mat Martineau84084a32011-07-22 14:54:00 -07003658 err = chan->ops->recv(chan->data, skb);
3659 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003660
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003661 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003662 if (chan->sdu)
3663 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003664
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003665 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003666 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003667
Mat Martineau84084a32011-07-22 14:54:00 -07003668 if (chan->sdu_len > chan->imtu) {
3669 err = -EMSGSIZE;
3670 break;
3671 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003672
Mat Martineau84084a32011-07-22 14:54:00 -07003673 if (skb->len >= chan->sdu_len)
3674 break;
3675
3676 chan->sdu = skb;
3677 chan->sdu_last_frag = skb;
3678
3679 skb = NULL;
3680 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003681 break;
3682
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003683 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003684 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003685 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003686
Mat Martineau84084a32011-07-22 14:54:00 -07003687 append_skb_frag(chan->sdu, skb,
3688 &chan->sdu_last_frag);
3689 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003690
Mat Martineau84084a32011-07-22 14:54:00 -07003691 if (chan->sdu->len >= chan->sdu_len)
3692 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003693
Mat Martineau84084a32011-07-22 14:54:00 -07003694 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003695 break;
3696
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003697 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003698 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003699 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003700
Mat Martineau84084a32011-07-22 14:54:00 -07003701 append_skb_frag(chan->sdu, skb,
3702 &chan->sdu_last_frag);
3703 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003704
Mat Martineau84084a32011-07-22 14:54:00 -07003705 if (chan->sdu->len != chan->sdu_len)
3706 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003707
Mat Martineau84084a32011-07-22 14:54:00 -07003708 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003709
Mat Martineau84084a32011-07-22 14:54:00 -07003710 if (!err) {
3711 /* Reassembly complete */
3712 chan->sdu = NULL;
3713 chan->sdu_last_frag = NULL;
3714 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003715 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003716 break;
3717 }
3718
Mat Martineau84084a32011-07-22 14:54:00 -07003719 if (err) {
3720 kfree_skb(skb);
3721 kfree_skb(chan->sdu);
3722 chan->sdu = NULL;
3723 chan->sdu_last_frag = NULL;
3724 chan->sdu_len = 0;
3725 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003726
Mat Martineau84084a32011-07-22 14:54:00 -07003727 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003728}
3729
Mat Martineau26f880d2011-07-07 09:39:01 -07003730static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003731{
Mat Martineau26f880d2011-07-07 09:39:01 -07003732 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003733
Mat Martineau26f880d2011-07-07 09:39:01 -07003734 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3735
Szymon Janc77f918b2012-01-11 10:59:48 +01003736 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003737}
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
Szymon Janc77f918b2012-01-11 10:59:48 +01003876 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3877 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3878 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003879 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003880 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003881
Mat Martineau02f1b642011-06-29 14:35:19 -07003882 if (tx_seq == chan->expected_tx_seq)
3883 goto expected;
3884
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003885 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003886 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003887
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003888 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003889 struct srej_list, list);
3890 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003891 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003892 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003893
3894 list_del(&first->list);
3895 kfree(first);
3896
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003897 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003898 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003899 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003900 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003901 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003902 }
3903 } else {
3904 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003905
3906 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003907 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003908 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003909
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003910 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003911 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003912 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003913 return 0;
3914 }
3915 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003916
3917 err = l2cap_send_srejframe(chan, tx_seq);
3918 if (err < 0) {
3919 l2cap_send_disconn_req(chan->conn, chan, -err);
3920 return err;
3921 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003922 }
3923 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003924 expected_tx_seq_offset = __seq_offset(chan,
3925 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003926
3927 /* duplicated tx_seq */
3928 if (tx_seq_offset < expected_tx_seq_offset)
3929 goto drop;
3930
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003931 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003932
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003933 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003934
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003935 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003936 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003937
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003938 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003939 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003940
Szymon Janc0ef3ef02012-01-11 10:59:46 +01003941 /* Set P-bit only if there are some I-frames to ack. */
3942 if (__clear_ack_timer(chan))
3943 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003944
Szymon Jancaef89f22011-11-16 09:32:18 +01003945 err = l2cap_send_srejframe(chan, tx_seq);
3946 if (err < 0) {
3947 l2cap_send_disconn_req(chan->conn, chan, -err);
3948 return err;
3949 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003950 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003951 return 0;
3952
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003953expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003954 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003955
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003956 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003957 bt_cb(skb)->tx_seq = tx_seq;
3958 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003959 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003960 return 0;
3961 }
3962
Mat Martineau84084a32011-07-22 14:54:00 -07003963 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003964 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
3965
Mat Martineaue3281402011-07-07 09:39:02 -07003966 if (err < 0) {
3967 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3968 return err;
3969 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003970
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003971 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003972 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003973 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003974 }
3975
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003976
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003977 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3978 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003979 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03003980 else
3981 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003982
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003983 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003984
3985drop:
3986 kfree_skb(skb);
3987 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003988}
3989
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003990static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003991{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003992 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003993 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003994
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003995 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003996 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003997
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003998 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003999 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4000 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4001 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004002 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004003 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004004
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004005 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004006 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004007 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004008 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004009 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004010
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004011 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004012 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004013
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004014 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004015 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004016
4017 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004018 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004019 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004020 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004021
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004022 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4023 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004024 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004025 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004026 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004027 }
4028}
4029
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004030static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004031{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004032 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004033
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004034 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004035
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004036 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004037
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004038 chan->expected_ack_seq = tx_seq;
4039 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004040
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004041 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004042 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004043 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004044 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004045 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004046
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004047 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4048 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004049 }
4050}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004051static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004052{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004053 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004054
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004055 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004056
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004057 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004058
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004059 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004060 chan->expected_ack_seq = tx_seq;
4061 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004062
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004063 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004064 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004065
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004066 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004067
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004068 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004069 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004070 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004071 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004072 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004073 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004074 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004075 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004076 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004077 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004078 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004079 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004080 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004081 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004082 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004083 }
4084 }
4085}
4086
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004087static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004088{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004089 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004090
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004091 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004092
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004093 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004094 chan->expected_ack_seq = tx_seq;
4095 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004096
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004097 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004098 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004099
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004100 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004101 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004102 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004103 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004104 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004105 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004106
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004107 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004108 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004109 } else {
4110 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4111 l2cap_send_sframe(chan, rx_control);
4112 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004113}
4114
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004115static 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 -03004116{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004117 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004118
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004119 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004120 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004121 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004122 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004123 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004124 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004125 }
4126
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004127 switch (__get_ctrl_super(chan, rx_control)) {
4128 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004129 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004130 break;
4131
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004132 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004133 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004134 break;
4135
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004136 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004137 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004138 break;
4139
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004140 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004141 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004142 break;
4143 }
4144
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004145 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004146 return 0;
4147}
4148
Szymon Janccad8f1d02012-01-23 10:06:05 +01004149static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004150{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004151 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004152 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004153 int len, next_tx_seq_offset, req_seq_offset;
4154
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004155 control = __get_control(chan, skb->data);
4156 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004157 len = skb->len;
4158
4159 /*
4160 * We can just drop the corrupted I-frame here.
4161 * Receiver will miss it and start proper recovery
4162 * procedures and ask retransmission.
4163 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004164 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004165 goto drop;
4166
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004167 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004168 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004169
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004170 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004171 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004172
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004173 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004174 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004175 goto drop;
4176 }
4177
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004178 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004179
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004180 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4181
4182 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4183 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004184
4185 /* check for invalid req-seq */
4186 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004187 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004188 goto drop;
4189 }
4190
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004191 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004192 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004193 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004194 goto drop;
4195 }
4196
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004197 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004198 } else {
4199 if (len != 0) {
4200 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004201 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004202 goto drop;
4203 }
4204
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004205 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004206 }
4207
4208 return 0;
4209
4210drop:
4211 kfree_skb(skb);
4212 return 0;
4213}
4214
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4216{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004217 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07004218 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004219 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004220 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004221 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004222
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004223 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004224 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 BT_DBG("unknown cid 0x%4.4x", cid);
4226 goto drop;
4227 }
4228
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004229 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004230
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004231 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004232
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004233 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 goto drop;
4235
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004236 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004237 case L2CAP_MODE_BASIC:
4238 /* If socket recv buffers overflows we drop data here
4239 * which is *bad* because L2CAP has to be reliable.
4240 * But we don't have any other choice. L2CAP doesn't
4241 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004243 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004244 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004246 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004247 goto done;
4248 break;
4249
4250 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004251 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004252
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004253 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004254
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004255 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004256 control = __get_control(chan, skb->data);
4257 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004258 len = skb->len;
4259
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004260 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004261 goto drop;
4262
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004263 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004264 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004265
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004266 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004267 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004268
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004269 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004270 goto drop;
4271
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004272 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004273
Mat Martineau84084a32011-07-22 14:54:00 -07004274 if (chan->expected_tx_seq != tx_seq) {
4275 /* Frame(s) missing - must discard partial SDU */
4276 kfree_skb(chan->sdu);
4277 chan->sdu = NULL;
4278 chan->sdu_last_frag = NULL;
4279 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004280
Mat Martineau84084a32011-07-22 14:54:00 -07004281 /* TODO: Notify userland of missing data */
4282 }
4283
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004284 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004285
4286 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4287 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004288
4289 goto done;
4290
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004291 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004292 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004293 break;
4294 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295
4296drop:
4297 kfree_skb(skb);
4298
4299done:
Marcel Holtmann01394182006-07-03 10:02:46 +02004300 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004301 release_sock(sk);
Marcel Holtmann01394182006-07-03 10:02:46 +02004302
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 return 0;
4304}
4305
Al Viro8e036fc2007-07-29 00:16:36 -07004306static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004308 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004309 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004311 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4312 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313 goto drop;
4314
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004315 sk = chan->sk;
4316
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004317 lock_sock(sk);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00004318
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 BT_DBG("sk %p, len %d", sk, skb->len);
4320
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004321 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 goto drop;
4323
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004324 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004325 goto drop;
4326
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004327 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 goto done;
4329
4330drop:
4331 kfree_skb(skb);
4332
4333done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004334 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004335 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 return 0;
4337}
4338
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004339static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4340{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004341 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004342 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004343
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004344 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4345 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004346 goto drop;
4347
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004348 sk = chan->sk;
4349
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004350 lock_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004351
4352 BT_DBG("sk %p, len %d", sk, skb->len);
4353
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004354 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004355 goto drop;
4356
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004357 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004358 goto drop;
4359
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004360 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004361 goto done;
4362
4363drop:
4364 kfree_skb(skb);
4365
4366done:
4367 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004368 release_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004369 return 0;
4370}
4371
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4373{
4374 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004375 u16 cid, len;
4376 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377
4378 skb_pull(skb, L2CAP_HDR_SIZE);
4379 cid = __le16_to_cpu(lh->cid);
4380 len = __le16_to_cpu(lh->len);
4381
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004382 if (len != skb->len) {
4383 kfree_skb(skb);
4384 return;
4385 }
4386
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4388
4389 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004390 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004391 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392 l2cap_sig_channel(conn, skb);
4393 break;
4394
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004395 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004396 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397 skb_pull(skb, 2);
4398 l2cap_conless_channel(conn, psm, skb);
4399 break;
4400
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004401 case L2CAP_CID_LE_DATA:
4402 l2cap_att_channel(conn, cid, skb);
4403 break;
4404
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004405 case L2CAP_CID_SMP:
4406 if (smp_sig_channel(conn, skb))
4407 l2cap_conn_del(conn->hcon, EACCES);
4408 break;
4409
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 default:
4411 l2cap_data_channel(conn, cid, skb);
4412 break;
4413 }
4414}
4415
4416/* ---- L2CAP interface with lower layer (HCI) ---- */
4417
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004418int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419{
4420 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004421 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4424
4425 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004426 read_lock(&chan_list_lock);
4427 list_for_each_entry(c, &chan_list, global_l) {
4428 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004429
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004430 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 continue;
4432
4433 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004434 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004435 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004436 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004438 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4439 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004440 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004441 lm2 |= HCI_LM_MASTER;
4442 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004444 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445
4446 return exact ? lm1 : lm2;
4447}
4448
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004449int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450{
Marcel Holtmann01394182006-07-03 10:02:46 +02004451 struct l2cap_conn *conn;
4452
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4454
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456 conn = l2cap_conn_add(hcon, status);
4457 if (conn)
4458 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004459 } else
Joe Perchese1750722011-06-29 18:18:29 -07004460 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004461
4462 return 0;
4463}
4464
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004465int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004466{
4467 struct l2cap_conn *conn = hcon->l2cap_data;
4468
4469 BT_DBG("hcon %p", hcon);
4470
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004471 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004472 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004473 return conn->disc_reason;
4474}
4475
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004476int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004477{
4478 BT_DBG("hcon %p reason %d", hcon, reason);
4479
Joe Perchese1750722011-06-29 18:18:29 -07004480 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481 return 0;
4482}
4483
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004484static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004485{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004486 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004487 return;
4488
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004489 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004490 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004491 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004492 __set_chan_timer(chan,
4493 msecs_to_jiffies(L2CAP_ENC_TIMEOUT));
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004494 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004495 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004496 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004497 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004498 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004499 }
4500}
4501
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004502int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004504 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004505 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506
Marcel Holtmann01394182006-07-03 10:02:46 +02004507 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004509
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510 BT_DBG("conn %p", conn);
4511
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004512 if (hcon->type == LE_LINK) {
4513 smp_distribute_keys(conn, 0);
Ulisses Furquim17cd3f32012-01-30 18:26:28 -02004514 cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004515 }
4516
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004517 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004519 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004520 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004521
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 bh_lock_sock(sk);
4523
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004524 BT_DBG("chan->scid %d", chan->scid);
4525
4526 if (chan->scid == L2CAP_CID_LE_DATA) {
4527 if (!status && encrypt) {
4528 chan->sec_level = hcon->sec_level;
Andrei Emeltchenkocf4cd002012-02-06 15:03:59 +02004529 l2cap_chan_ready(chan);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004530 }
4531
4532 bh_unlock_sock(sk);
4533 continue;
4534 }
4535
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004536 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004537 bh_unlock_sock(sk);
4538 continue;
4539 }
4540
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004541 if (!status && (chan->state == BT_CONNECTED ||
4542 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004543 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004544 bh_unlock_sock(sk);
4545 continue;
4546 }
4547
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004548 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004549 if (!status) {
4550 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004551 req.scid = cpu_to_le16(chan->scid);
4552 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004553
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004554 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004555 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004556
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004557 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004558 L2CAP_CONN_REQ, sizeof(req), &req);
4559 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004560 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004561 __set_chan_timer(chan,
4562 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004563 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004564 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004565 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004566 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004567
4568 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004569 if (bt_sk(sk)->defer_setup) {
4570 struct sock *parent = bt_sk(sk)->parent;
4571 res = L2CAP_CR_PEND;
4572 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004573 if (parent)
4574 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004575 } else {
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004576 l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004577 res = L2CAP_CR_SUCCESS;
4578 stat = L2CAP_CS_NO_INFO;
4579 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004580 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004581 l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004582 __set_chan_timer(chan,
4583 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004584 res = L2CAP_CR_SEC_BLOCK;
4585 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004586 }
4587
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004588 rsp.scid = cpu_to_le16(chan->dcid);
4589 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004590 rsp.result = cpu_to_le16(res);
4591 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004592 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4593 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 }
4595
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 bh_unlock_sock(sk);
4597 }
4598
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004599 rcu_read_unlock();
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004600
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 return 0;
4602}
4603
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004604int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605{
4606 struct l2cap_conn *conn = hcon->l2cap_data;
4607
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004608 if (!conn)
4609 conn = l2cap_conn_add(hcon, 0);
4610
4611 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 goto drop;
4613
4614 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4615
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004616 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004618 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004619 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 int len;
4621
4622 if (conn->rx_len) {
4623 BT_ERR("Unexpected start frame (len %d)", skb->len);
4624 kfree_skb(conn->rx_skb);
4625 conn->rx_skb = NULL;
4626 conn->rx_len = 0;
4627 l2cap_conn_unreliable(conn, ECOMM);
4628 }
4629
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004630 /* Start fragment always begin with Basic L2CAP header */
4631 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 BT_ERR("Frame is too short (len %d)", skb->len);
4633 l2cap_conn_unreliable(conn, ECOMM);
4634 goto drop;
4635 }
4636
4637 hdr = (struct l2cap_hdr *) skb->data;
4638 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004639 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640
4641 if (len == skb->len) {
4642 /* Complete frame received */
4643 l2cap_recv_frame(conn, skb);
4644 return 0;
4645 }
4646
4647 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4648
4649 if (skb->len > len) {
4650 BT_ERR("Frame is too long (len %d, expected len %d)",
4651 skb->len, len);
4652 l2cap_conn_unreliable(conn, ECOMM);
4653 goto drop;
4654 }
4655
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004656 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004657
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004658 if (chan && chan->sk) {
4659 struct sock *sk = chan->sk;
4660
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004661 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004662 BT_ERR("Frame exceeding recv MTU (len %d, "
4663 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004664 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004665 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004666 l2cap_conn_unreliable(conn, ECOMM);
4667 goto drop;
4668 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004669 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004670 }
4671
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004673 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4674 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 goto drop;
4676
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004677 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004678 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 conn->rx_len = len - skb->len;
4680 } else {
4681 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4682
4683 if (!conn->rx_len) {
4684 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4685 l2cap_conn_unreliable(conn, ECOMM);
4686 goto drop;
4687 }
4688
4689 if (skb->len > conn->rx_len) {
4690 BT_ERR("Fragment is too long (len %d, expected %d)",
4691 skb->len, conn->rx_len);
4692 kfree_skb(conn->rx_skb);
4693 conn->rx_skb = NULL;
4694 conn->rx_len = 0;
4695 l2cap_conn_unreliable(conn, ECOMM);
4696 goto drop;
4697 }
4698
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004699 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004700 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 conn->rx_len -= skb->len;
4702
4703 if (!conn->rx_len) {
4704 /* Complete frame received */
4705 l2cap_recv_frame(conn, conn->rx_skb);
4706 conn->rx_skb = NULL;
4707 }
4708 }
4709
4710drop:
4711 kfree_skb(skb);
4712 return 0;
4713}
4714
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004715static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004717 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004719 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004721 list_for_each_entry(c, &chan_list, global_l) {
4722 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004724 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 +01004725 batostr(&bt_sk(sk)->src),
4726 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004727 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004728 c->scid, c->dcid, c->imtu, c->omtu,
4729 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004730 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004732 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004733
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004734 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735}
4736
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004737static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4738{
4739 return single_open(file, l2cap_debugfs_show, inode->i_private);
4740}
4741
4742static const struct file_operations l2cap_debugfs_fops = {
4743 .open = l2cap_debugfs_open,
4744 .read = seq_read,
4745 .llseek = seq_lseek,
4746 .release = single_release,
4747};
4748
4749static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004751int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752{
4753 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004754
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004755 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 if (err < 0)
4757 return err;
4758
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004759 if (bt_debugfs) {
4760 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4761 bt_debugfs, NULL, &l2cap_debugfs_fops);
4762 if (!l2cap_debugfs)
4763 BT_ERR("Failed to create L2CAP debug file");
4764 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767}
4768
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004769void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004771 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004772 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773}
4774
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004775module_param(disable_ertm, bool, 0644);
4776MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");