blob: 584a4237eb3fccf73b1283de72d2df8ab566f347 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
7 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation;
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090017 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090022 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 SOFTWARE IS DISCLAIMED.
25*/
26
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020027/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30
31#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/sched.h>
36#include <linux/slab.h>
37#include <linux/poll.h>
38#include <linux/fcntl.h>
39#include <linux/init.h>
40#include <linux/interrupt.h>
41#include <linux/socket.h>
42#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080044#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010045#include <linux/debugfs.h>
46#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030047#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030048#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/sock.h>
50
51#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/unaligned.h>
53
54#include <net/bluetooth/bluetooth.h>
55#include <net/bluetooth/hci_core.h>
56#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030057#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020059int disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020060
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070061static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Marcel Holtmanne1027a72009-02-09 09:18:02 +010062static u8 l2cap_fixed_chan[8] = { 0x02, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Gustavo F. Padovan1890d362010-05-01 16:15:44 -030064static struct workqueue_struct *_busy_wq;
65
Johannes Bergb5ad8b72011-06-01 08:54:45 +020066static LIST_HEAD(chan_list);
67static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Gustavo F. Padovan1890d362010-05-01 16:15:44 -030069static void l2cap_busy_work(struct work_struct *work);
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
72 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030073static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
74 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030075static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030076static void l2cap_send_disconn_req(struct l2cap_conn *conn,
77 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030079static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
80
Marcel Holtmann01394182006-07-03 10:02:46 +020081/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030082
83static inline void chan_hold(struct l2cap_chan *c)
84{
85 atomic_inc(&c->refcnt);
86}
87
88static inline void chan_put(struct l2cap_chan *c)
89{
90 if (atomic_dec_and_test(&c->refcnt))
91 kfree(c);
92}
93
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030094static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020095{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030096 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030097
98 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030099 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300100 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200101 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300102 return NULL;
103
Marcel Holtmann01394182006-07-03 10:02:46 +0200104}
105
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300106static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200107{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300108 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300109
110 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300111 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300112 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200113 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300114 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200115}
116
117/* Find channel with given SCID.
118 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300119static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200120{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300121 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300122
123 read_lock(&conn->chan_lock);
124 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300125 if (c)
126 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300127 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300128 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200129}
130
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300131static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200132{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300133 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300134
135 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300136 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300137 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200138 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300139 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200140}
141
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300142static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200143{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300144 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300145
146 read_lock(&conn->chan_lock);
147 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300148 if (c)
149 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300150 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300151 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200152}
153
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300154static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300155{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300156 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300157
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300158 list_for_each_entry(c, &chan_list, global_l) {
159 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300160 goto found;
161 }
162
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300163 c = NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300164found:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300165 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300166}
167
168int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
169{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300170 int err;
171
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300172 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300173
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300174 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300175 err = -EADDRINUSE;
176 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300177 }
178
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300179 if (psm) {
180 chan->psm = psm;
181 chan->sport = psm;
182 err = 0;
183 } else {
184 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300185
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300186 err = -EINVAL;
187 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300188 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300189 chan->psm = cpu_to_le16(p);
190 chan->sport = cpu_to_le16(p);
191 err = 0;
192 break;
193 }
194 }
195
196done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300197 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300198 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300199}
200
201int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
202{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300203 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300204
205 chan->scid = scid;
206
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300207 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300208
209 return 0;
210}
211
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300212static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200213{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300214 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200215
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300216 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300217 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200218 return cid;
219 }
220
221 return 0;
222}
223
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300224static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300225{
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300226 BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
227
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300228 if (!mod_timer(timer, jiffies + timeout))
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300229 chan_hold(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300230}
231
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300232static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300233{
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300234 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300235
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300236 if (timer_pending(timer) && del_timer(timer))
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300237 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300238}
239
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300240static void l2cap_state_change(struct l2cap_chan *chan, int state)
241{
242 chan->state = state;
243 chan->ops->state_change(chan->data, state);
244}
245
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300246static void l2cap_chan_timeout(unsigned long arg)
247{
248 struct l2cap_chan *chan = (struct l2cap_chan *) arg;
249 struct sock *sk = chan->sk;
250 int reason;
251
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300252 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300253
254 bh_lock_sock(sk);
255
256 if (sock_owned_by_user(sk)) {
257 /* sk is owned by user. Try again later */
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300258 __set_chan_timer(chan, HZ / 5);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300259 bh_unlock_sock(sk);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300260 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300261 return;
262 }
263
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
274 bh_unlock_sock(sk);
275
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300276 chan->ops->close(chan->data);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300277 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. Padovan23691d72011-04-27 18:26:32 -0300290 write_lock_bh(&chan_list_lock);
291 list_add(&chan->global_l, &chan_list);
292 write_unlock_bh(&chan_list_lock);
293
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300294 setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
295
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
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300300 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200301}
302
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300303void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300304{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300305 write_lock_bh(&chan_list_lock);
306 list_del(&chan->global_l);
307 write_unlock_bh(&chan_list_lock);
308
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300309 chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300310}
311
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300312static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200313{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300314 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300315 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200316
Marcel Holtmann2950f212009-02-12 14:02:50 +0100317 conn->disc_reason = 0x13;
318
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300319 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200320
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300321 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300322 if (conn->hcon->type == LE_LINK) {
323 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300324 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300325 chan->scid = L2CAP_CID_LE_DATA;
326 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300327 } else {
328 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300329 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300330 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300331 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300332 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200333 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300334 chan->scid = L2CAP_CID_CONN_LESS;
335 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300336 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200337 } else {
338 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300339 chan->scid = L2CAP_CID_SIGNALING;
340 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300341 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200342 }
343
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300344 chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300345
346 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200347}
348
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900349/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200350 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300351static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200352{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300353 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300354 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200355 struct sock *parent = bt_sk(sk)->parent;
356
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300357 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200358
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300359 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200360
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900361 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300362 /* Delete from channel list */
363 write_lock_bh(&conn->chan_lock);
364 list_del(&chan->list);
365 write_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300366 chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300367
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300368 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200369 hci_conn_put(conn->hcon);
370 }
371
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300372 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200373 sock_set_flag(sk, SOCK_ZAPPED);
374
375 if (err)
376 sk->sk_err = err;
377
378 if (parent) {
379 bt_accept_unlink(sk);
380 parent->sk_data_ready(parent, 0);
381 } else
382 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300383
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300384 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE &&
385 chan->conf_state & L2CAP_CONF_INPUT_DONE))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300386 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300387
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300388 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300389
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300390 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300391 struct srej_list *l, *tmp;
392
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300393 __clear_retrans_timer(chan);
394 __clear_monitor_timer(chan);
395 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300396
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300397 skb_queue_purge(&chan->srej_q);
398 skb_queue_purge(&chan->busy_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300399
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300400 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300401 list_del(&l->list);
402 kfree(l);
403 }
404 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200405}
406
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300407static void l2cap_chan_cleanup_listen(struct sock *parent)
408{
409 struct sock *sk;
410
411 BT_DBG("parent %p", parent);
412
413 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300414 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300415 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300416 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300417 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300418 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300419 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300420 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300421 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300422}
423
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300424void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300425{
426 struct l2cap_conn *conn = chan->conn;
427 struct sock *sk = chan->sk;
428
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300429 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300430
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300431 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300432 case BT_LISTEN:
433 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300434
435 l2cap_state_change(chan, BT_CLOSED);
436 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300437 break;
438
439 case BT_CONNECTED:
440 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300441 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300442 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300443 __clear_chan_timer(chan);
444 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300445 l2cap_send_disconn_req(conn, chan, reason);
446 } else
447 l2cap_chan_del(chan, reason);
448 break;
449
450 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300451 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300452 conn->hcon->type == ACL_LINK) {
453 struct l2cap_conn_rsp rsp;
454 __u16 result;
455
456 if (bt_sk(sk)->defer_setup)
457 result = L2CAP_CR_SEC_BLOCK;
458 else
459 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300460 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300461
462 rsp.scid = cpu_to_le16(chan->dcid);
463 rsp.dcid = cpu_to_le16(chan->scid);
464 rsp.result = cpu_to_le16(result);
465 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
466 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
467 sizeof(rsp), &rsp);
468 }
469
470 l2cap_chan_del(chan, reason);
471 break;
472
473 case BT_CONNECT:
474 case BT_DISCONN:
475 l2cap_chan_del(chan, reason);
476 break;
477
478 default:
479 sock_set_flag(sk, SOCK_ZAPPED);
480 break;
481 }
482}
483
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300484static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530485{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300486 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300487 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530488 case BT_SECURITY_HIGH:
489 return HCI_AT_DEDICATED_BONDING_MITM;
490 case BT_SECURITY_MEDIUM:
491 return HCI_AT_DEDICATED_BONDING;
492 default:
493 return HCI_AT_NO_BONDING;
494 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300495 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300496 if (chan->sec_level == BT_SECURITY_LOW)
497 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530498
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300499 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530500 return HCI_AT_NO_BONDING_MITM;
501 else
502 return HCI_AT_NO_BONDING;
503 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300504 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530505 case BT_SECURITY_HIGH:
506 return HCI_AT_GENERAL_BONDING_MITM;
507 case BT_SECURITY_MEDIUM:
508 return HCI_AT_GENERAL_BONDING;
509 default:
510 return HCI_AT_NO_BONDING;
511 }
512 }
513}
514
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200515/* Service level security */
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300516static inline int l2cap_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200517{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300518 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100519 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200520
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300521 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100522
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300523 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200524}
525
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200526static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200527{
528 u8 id;
529
530 /* Get next available identificator.
531 * 1 - 128 are used by kernel.
532 * 129 - 199 are reserved.
533 * 200 - 254 are used by utilities like l2ping, etc.
534 */
535
536 spin_lock_bh(&conn->lock);
537
538 if (++conn->tx_ident > 128)
539 conn->tx_ident = 1;
540
541 id = conn->tx_ident;
542
543 spin_unlock_bh(&conn->lock);
544
545 return id;
546}
547
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300548static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200549{
550 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200551 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200552
553 BT_DBG("code 0x%2.2x", code);
554
555 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300556 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200557
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200558 if (lmp_no_flush_capable(conn->hcon->hdev))
559 flags = ACL_START_NO_FLUSH;
560 else
561 flags = ACL_START;
562
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700563 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
564
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200565 hci_send_acl(conn->hcon, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200566}
567
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300568static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300569{
570 struct sk_buff *skb;
571 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300572 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300573 int count, hlen = L2CAP_HDR_SIZE + 2;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200574 u8 flags;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300575
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300576 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300577 return;
578
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300579 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300580 hlen += 2;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300581
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300582 BT_DBG("chan %p, control 0x%2.2x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300583
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300584 count = min_t(unsigned int, conn->mtu, hlen);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300585 control |= L2CAP_CTRL_FRAME_TYPE;
586
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300587 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300588 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300589 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300590 }
591
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300592 if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300593 control |= L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300594 chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300595 }
596
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300597 skb = bt_skb_alloc(count, GFP_ATOMIC);
598 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300599 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300600
601 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300602 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300603 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300604 put_unaligned_le16(control, skb_put(skb, 2));
605
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300606 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300607 u16 fcs = crc16(0, (u8 *)lh, count - 2);
608 put_unaligned_le16(fcs, skb_put(skb, 2));
609 }
610
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200611 if (lmp_no_flush_capable(conn->hcon->hdev))
612 flags = ACL_START_NO_FLUSH;
613 else
614 flags = ACL_START;
615
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700616 bt_cb(skb)->force_active = chan->force_active;
617
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300618 hci_send_acl(chan->conn->hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300619}
620
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300621static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300622{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300623 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300624 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300625 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300626 } else
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300627 control |= L2CAP_SUPER_RCV_READY;
628
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -0300629 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300630
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300631 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300632}
633
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300634static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300635{
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300636 return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300637}
638
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300639static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200640{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300641 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200642
643 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100644 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
645 return;
646
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300647 if (l2cap_check_security(chan) &&
648 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200649 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300650 req.scid = cpu_to_le16(chan->scid);
651 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200652
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300653 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300654 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200655
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300656 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
657 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200658 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200659 } else {
660 struct l2cap_info_req req;
661 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
662
663 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
664 conn->info_ident = l2cap_get_ident(conn);
665
666 mod_timer(&conn->info_timer, jiffies +
667 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
668
669 l2cap_send_cmd(conn, conn->info_ident,
670 L2CAP_INFO_REQ, sizeof(req), &req);
671 }
672}
673
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300674static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
675{
676 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300677 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300678 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
679
680 switch (mode) {
681 case L2CAP_MODE_ERTM:
682 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
683 case L2CAP_MODE_STREAMING:
684 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
685 default:
686 return 0x00;
687 }
688}
689
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300690static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300691{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300692 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300693 struct l2cap_disconn_req req;
694
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300695 if (!conn)
696 return;
697
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300698 sk = chan->sk;
699
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300700 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300701 __clear_retrans_timer(chan);
702 __clear_monitor_timer(chan);
703 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300704 }
705
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300706 req.dcid = cpu_to_le16(chan->dcid);
707 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300708 l2cap_send_cmd(conn, l2cap_get_ident(conn),
709 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300710
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300711 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300712 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300713}
714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200716static void l2cap_conn_start(struct l2cap_conn *conn)
717{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300718 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200719
720 BT_DBG("conn %p", conn);
721
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300722 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200723
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300724 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300725 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300726
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200727 bh_lock_sock(sk);
728
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300729 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200730 bh_unlock_sock(sk);
731 continue;
732 }
733
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300734 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300735 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300736
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300737 if (!l2cap_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300738 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300739 bh_unlock_sock(sk);
740 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200741 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300742
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300743 if (!l2cap_mode_supported(chan->mode,
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300744 conn->feat_mask)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300745 && chan->conf_state &
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300746 L2CAP_CONF_STATE2_DEVICE) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300747 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300748 * so release the lock */
749 read_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300750 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300751 read_lock_bh(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300752 bh_unlock_sock(sk);
753 continue;
754 }
755
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300756 req.scid = cpu_to_le16(chan->scid);
757 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300758
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300759 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300760 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300761
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300762 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
763 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300764
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300765 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200766 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300767 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300768 rsp.scid = cpu_to_le16(chan->dcid);
769 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200770
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300771 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100772 if (bt_sk(sk)->defer_setup) {
773 struct sock *parent = bt_sk(sk)->parent;
774 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
775 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
776 parent->sk_data_ready(parent, 0);
777
778 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300779 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100780 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
781 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
782 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200783 } else {
784 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
785 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
786 }
787
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300788 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
789 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300790
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300791 if (chan->conf_state & L2CAP_CONF_REQ_SENT ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300792 rsp.result != L2CAP_CR_SUCCESS) {
793 bh_unlock_sock(sk);
794 continue;
795 }
796
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300797 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300798 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300799 l2cap_build_conf_req(chan, buf), buf);
800 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200801 }
802
803 bh_unlock_sock(sk);
804 }
805
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300806 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200807}
808
Ville Tervob62f3282011-02-10 22:38:50 -0300809/* Find socket with cid and source bdaddr.
810 * Returns closest match, locked.
811 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300812static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300813{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300814 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300815
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300816 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300817
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300818 list_for_each_entry(c, &chan_list, global_l) {
819 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300820
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300821 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300822 continue;
823
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300824 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300825 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300826 if (!bacmp(&bt_sk(sk)->src, src)) {
827 read_unlock(&chan_list_lock);
828 return c;
829 }
Ville Tervob62f3282011-02-10 22:38:50 -0300830
831 /* Closest match */
832 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300833 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300834 }
835 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300836
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300837 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300838
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300839 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300840}
841
842static void l2cap_le_conn_ready(struct l2cap_conn *conn)
843{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300844 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300845 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300846
847 BT_DBG("");
848
849 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300850 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300851 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300852 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300853 return;
854
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300855 parent = pchan->sk;
856
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300857 bh_lock_sock(parent);
858
Ville Tervob62f3282011-02-10 22:38:50 -0300859 /* Check for backlog size */
860 if (sk_acceptq_is_full(parent)) {
861 BT_DBG("backlog full %d", parent->sk_ack_backlog);
862 goto clean;
863 }
864
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300865 chan = pchan->ops->new_connection(pchan->data);
866 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300867 goto clean;
868
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300869 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300870
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300871 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300872
873 hci_conn_hold(conn->hcon);
874
Ville Tervob62f3282011-02-10 22:38:50 -0300875 bacpy(&bt_sk(sk)->src, conn->src);
876 bacpy(&bt_sk(sk)->dst, conn->dst);
877
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300878 bt_accept_enqueue(parent, sk);
879
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300880 __l2cap_chan_add(conn, chan);
881
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300882 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300883
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300884 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300885 parent->sk_data_ready(parent, 0);
886
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300887 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300888
889clean:
890 bh_unlock_sock(parent);
891}
892
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300893static void l2cap_chan_ready(struct sock *sk)
894{
895 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
896 struct sock *parent = bt_sk(sk)->parent;
897
898 BT_DBG("sk %p, parent %p", sk, parent);
899
900 chan->conf_state = 0;
901 __clear_chan_timer(chan);
902
903 sk->sk_state = BT_CONNECTED;
904 sk->sk_state_change(sk);
905
906 if (parent)
907 parent->sk_data_ready(parent, 0);
908}
909
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200910static void l2cap_conn_ready(struct l2cap_conn *conn)
911{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300912 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200913
914 BT_DBG("conn %p", conn);
915
Ville Tervob62f3282011-02-10 22:38:50 -0300916 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
917 l2cap_le_conn_ready(conn);
918
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300919 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200920
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300921 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300922 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300923
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200924 bh_lock_sock(sk);
925
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300926 if (conn->hcon->type == LE_LINK)
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300927 if (smp_conn_security(conn, chan->sec_level))
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300928 l2cap_chan_ready(sk);
Ville Tervoacd7d372011-02-10 22:38:49 -0300929
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300930 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300931 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300932 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200933 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300934
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300935 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300936 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200937
938 bh_unlock_sock(sk);
939 }
940
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300941 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200942}
943
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200944/* Notify sockets that we cannot guaranty reliability anymore */
945static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
946{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300947 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200948
949 BT_DBG("conn %p", conn);
950
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300951 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200952
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300953 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300954 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300955
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300956 if (chan->force_reliable)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200957 sk->sk_err = err;
958 }
959
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300960 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200961}
962
963static void l2cap_info_timeout(unsigned long arg)
964{
965 struct l2cap_conn *conn = (void *) arg;
966
Marcel Holtmann984947d2009-02-06 23:35:19 +0100967 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100968 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100969
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200970 l2cap_conn_start(conn);
971}
972
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
974{
Marcel Holtmann01394182006-07-03 10:02:46 +0200975 struct l2cap_conn *conn = hcon->l2cap_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Marcel Holtmann01394182006-07-03 10:02:46 +0200977 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 return conn;
979
Marcel Holtmann01394182006-07-03 10:02:46 +0200980 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
981 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
984 hcon->l2cap_data = conn;
985 conn->hcon = hcon;
986
Marcel Holtmann01394182006-07-03 10:02:46 +0200987 BT_DBG("hcon %p conn %p", hcon, conn);
988
Ville Tervoacd7d372011-02-10 22:38:49 -0300989 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
990 conn->mtu = hcon->hdev->le_mtu;
991 else
992 conn->mtu = hcon->hdev->acl_mtu;
993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 conn->src = &hcon->hdev->bdaddr;
995 conn->dst = &hcon->dst;
996
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200997 conn->feat_mask = 0;
998
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001000 rwlock_init(&conn->chan_lock);
1001
1002 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
Ville Tervob62f3282011-02-10 22:38:50 -03001004 if (hcon->type != LE_LINK)
1005 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +00001006 (unsigned long) conn);
1007
Marcel Holtmann2950f212009-02-12 14:02:50 +01001008 conn->disc_reason = 0x13;
1009
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 return conn;
1011}
1012
Marcel Holtmann01394182006-07-03 10:02:46 +02001013static void l2cap_conn_del(struct hci_conn *hcon, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014{
Marcel Holtmann01394182006-07-03 10:02:46 +02001015 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001016 struct l2cap_chan *chan, *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 struct sock *sk;
1018
Marcel Holtmann01394182006-07-03 10:02:46 +02001019 if (!conn)
1020 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
1022 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1023
Wei Yongjun7585b972009-02-25 18:29:52 +08001024 kfree_skb(conn->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
1026 /* Kill channels */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001027 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001028 sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 bh_lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001030 l2cap_chan_del(chan, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 bh_unlock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03001032 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 }
1034
Dave Young8e8440f2008-03-03 12:18:55 -08001035 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
1036 del_timer_sync(&conn->info_timer);
Thomas Gleixner3ab22732008-02-26 17:42:56 -08001037
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 hcon->l2cap_data = NULL;
1039 kfree(conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040}
1041
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001042static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001044 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001045 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001046 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047}
1048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
1051/* Find socket with psm and source bdaddr.
1052 * Returns closest match.
1053 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001054static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001056 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001058 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001059
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001060 list_for_each_entry(c, &chan_list, global_l) {
1061 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001062
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001063 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 continue;
1065
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001066 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001068 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001069 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001070 return c;
1071 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073 /* Closest match */
1074 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001075 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 }
1077 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001079 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001080
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001081 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082}
1083
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001084int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001086 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 bdaddr_t *src = &bt_sk(sk)->src;
1088 bdaddr_t *dst = &bt_sk(sk)->dst;
1089 struct l2cap_conn *conn;
1090 struct hci_conn *hcon;
1091 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001092 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001093 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001095 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001096 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001098 hdev = hci_get_route(dst, src);
1099 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 return -EHOSTUNREACH;
1101
1102 hci_dev_lock_bh(hdev);
1103
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001104 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001105
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001106 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001107 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001108 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001109 else
1110 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001111 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001112
Ville Tervo30e76272011-02-22 16:10:53 -03001113 if (IS_ERR(hcon)) {
1114 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
1118 conn = l2cap_conn_add(hcon, 0);
1119 if (!conn) {
1120 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001121 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 goto done;
1123 }
1124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 /* Update source addr of the socket */
1126 bacpy(src, conn->src);
1127
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001128 l2cap_chan_add(conn, chan);
1129
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001130 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001131 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001134 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001135 __clear_chan_timer(chan);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001136 if (l2cap_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001137 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001138 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001139 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 }
1141
Ville Tervo30e76272011-02-22 16:10:53 -03001142 err = 0;
1143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144done:
1145 hci_dev_unlock_bh(hdev);
1146 hci_dev_put(hdev);
1147 return err;
1148}
1149
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001150int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001151{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001152 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001153 DECLARE_WAITQUEUE(wait, current);
1154 int err = 0;
1155 int timeo = HZ/5;
1156
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001157 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001158 while ((chan->unacked_frames > 0 && chan->conn)) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001159 set_current_state(TASK_INTERRUPTIBLE);
1160
1161 if (!timeo)
1162 timeo = HZ/5;
1163
1164 if (signal_pending(current)) {
1165 err = sock_intr_errno(timeo);
1166 break;
1167 }
1168
1169 release_sock(sk);
1170 timeo = schedule_timeout(timeo);
1171 lock_sock(sk);
1172
1173 err = sock_error(sk);
1174 if (err)
1175 break;
1176 }
1177 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001178 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001179 return err;
1180}
1181
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001182static void l2cap_monitor_timeout(unsigned long arg)
1183{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001184 struct l2cap_chan *chan = (void *) arg;
1185 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001186
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001187 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001188
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001189 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001190 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001191 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001192 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001193 return;
1194 }
1195
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001196 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001197 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001198
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001199 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001200 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001201}
1202
1203static void l2cap_retrans_timeout(unsigned long arg)
1204{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001205 struct l2cap_chan *chan = (void *) arg;
1206 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001207
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001208 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001209
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001210 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001211 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001212 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001213
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001214 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001215
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001216 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001217 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001218}
1219
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001220static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001221{
1222 struct sk_buff *skb;
1223
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001224 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001225 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001226 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001227 break;
1228
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001229 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001230 kfree_skb(skb);
1231
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001232 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001233 }
1234
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001235 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001236 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001237}
1238
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001239void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001240{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001241 struct hci_conn *hcon = chan->conn->hcon;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001242 u16 flags;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001243
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001244 BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001245
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001246 if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001247 flags = ACL_START_NO_FLUSH;
1248 else
1249 flags = ACL_START;
1250
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -07001251 bt_cb(skb)->force_active = chan->force_active;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001252 hci_send_acl(hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001253}
1254
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001255void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001256{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001257 struct sk_buff *skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001258 u16 control, fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001259
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001260 while ((skb = skb_dequeue(&chan->tx_q))) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001261 control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001262 control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001263 put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001264
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001265 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001266 fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
1267 put_unaligned_le16(fcs, skb->data + skb->len - 2);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001268 }
1269
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001270 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001271
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001272 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001273 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001274}
1275
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001276static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001277{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001278 struct sk_buff *skb, *tx_skb;
1279 u16 control, fcs;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001280
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001281 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001282 if (!skb)
1283 return;
1284
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001285 do {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001286 if (bt_cb(skb)->tx_seq == tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001287 break;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001288
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001289 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001290 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001291
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001292 } while ((skb = skb_queue_next(&chan->tx_q, skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001293
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001294 if (chan->remote_max_tx &&
1295 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001296 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001297 return;
1298 }
1299
1300 tx_skb = skb_clone(skb, GFP_ATOMIC);
1301 bt_cb(skb)->retries++;
1302 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Ruiyi Zhanga429b512011-04-18 11:04:30 +08001303 control &= L2CAP_CTRL_SAR;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001304
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001305 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001306 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001307 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001308 }
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001309
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001310 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001311 | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001312
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001313 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1314
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001315 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001316 fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
1317 put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
1318 }
1319
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001320 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001321}
1322
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001323int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001324{
1325 struct sk_buff *skb, *tx_skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001326 u16 control, fcs;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001327 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001328
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001329 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001330 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001331
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001332 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001333
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001334 if (chan->remote_max_tx &&
1335 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001336 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001337 break;
1338 }
1339
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001340 tx_skb = skb_clone(skb, GFP_ATOMIC);
1341
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001342 bt_cb(skb)->retries++;
1343
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001344 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001345 control &= L2CAP_CTRL_SAR;
1346
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001347 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001348 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001349 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001350 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001351 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
1352 | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001353 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1354
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001355
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001356 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001357 fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
1358 put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
1359 }
1360
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001361 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001362
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001363 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001364
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001365 bt_cb(skb)->tx_seq = chan->next_tx_seq;
1366 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001367
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301368 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001369 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301370
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001371 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001372
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001373 if (skb_queue_is_last(&chan->tx_q, skb))
1374 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001375 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001376 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001377
1378 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001379 }
1380
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001381 return nsent;
1382}
1383
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001384static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001385{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001386 int ret;
1387
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001388 if (!skb_queue_empty(&chan->tx_q))
1389 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001390
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001391 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001392 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001393 return ret;
1394}
1395
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001396static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001397{
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001398 u16 control = 0;
1399
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001400 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001401
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001402 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001403 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001404 chan->conn_state |= L2CAP_CONN_RNR_SENT;
1405 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001406 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001407 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001408
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001409 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001410 return;
1411
1412 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001413 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001414}
1415
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001416static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001417{
1418 struct srej_list *tail;
1419 u16 control;
1420
1421 control = L2CAP_SUPER_SELECT_REJECT;
1422 control |= L2CAP_CTRL_FINAL;
1423
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001424 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001425 control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
1426
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001427 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001428}
1429
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001430static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001432 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001433 struct sk_buff **frag;
1434 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001436 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001437 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438
1439 sent += count;
1440 len -= count;
1441
1442 /* Continuation fragments (no L2CAP header) */
1443 frag = &skb_shinfo(skb)->frag_list;
1444 while (len) {
1445 count = min_t(unsigned int, conn->mtu, len);
1446
1447 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1448 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001449 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001450 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1451 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
1453 sent += count;
1454 len -= count;
1455
1456 frag = &(*frag)->next;
1457 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
1459 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001460}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001462struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001463{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001464 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001465 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001466 struct sk_buff *skb;
1467 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1468 struct l2cap_hdr *lh;
1469
1470 BT_DBG("sk %p len %d", sk, (int)len);
1471
1472 count = min_t(unsigned int, (conn->mtu - hlen), len);
1473 skb = bt_skb_send_alloc(sk, count + hlen,
1474 msg->msg_flags & MSG_DONTWAIT, &err);
1475 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001476 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001477
1478 /* Create L2CAP header */
1479 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001480 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001481 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001482 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001483
1484 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1485 if (unlikely(err < 0)) {
1486 kfree_skb(skb);
1487 return ERR_PTR(err);
1488 }
1489 return skb;
1490}
1491
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001492struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001493{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001494 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001495 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001496 struct sk_buff *skb;
1497 int err, count, hlen = L2CAP_HDR_SIZE;
1498 struct l2cap_hdr *lh;
1499
1500 BT_DBG("sk %p len %d", sk, (int)len);
1501
1502 count = min_t(unsigned int, (conn->mtu - hlen), len);
1503 skb = bt_skb_send_alloc(sk, count + hlen,
1504 msg->msg_flags & MSG_DONTWAIT, &err);
1505 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001506 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001507
1508 /* Create L2CAP header */
1509 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001510 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001511 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1512
1513 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1514 if (unlikely(err < 0)) {
1515 kfree_skb(skb);
1516 return ERR_PTR(err);
1517 }
1518 return skb;
1519}
1520
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001521struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001522{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001523 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001524 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001525 struct sk_buff *skb;
1526 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1527 struct l2cap_hdr *lh;
1528
1529 BT_DBG("sk %p len %d", sk, (int)len);
1530
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001531 if (!conn)
1532 return ERR_PTR(-ENOTCONN);
1533
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001534 if (sdulen)
1535 hlen += 2;
1536
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001537 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001538 hlen += 2;
1539
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001540 count = min_t(unsigned int, (conn->mtu - hlen), len);
1541 skb = bt_skb_send_alloc(sk, count + hlen,
1542 msg->msg_flags & MSG_DONTWAIT, &err);
1543 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001544 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001545
1546 /* Create L2CAP header */
1547 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001548 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001549 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1550 put_unaligned_le16(control, skb_put(skb, 2));
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001551 if (sdulen)
1552 put_unaligned_le16(sdulen, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001553
1554 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1555 if (unlikely(err < 0)) {
1556 kfree_skb(skb);
1557 return ERR_PTR(err);
1558 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001559
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001560 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001561 put_unaligned_le16(0, skb_put(skb, 2));
1562
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001563 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001564 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565}
1566
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001567int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001568{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001569 struct sk_buff *skb;
1570 struct sk_buff_head sar_queue;
1571 u16 control;
1572 size_t size = 0;
1573
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001574 skb_queue_head_init(&sar_queue);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001575 control = L2CAP_SDU_START;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001576 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001577 if (IS_ERR(skb))
1578 return PTR_ERR(skb);
1579
1580 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001581 len -= chan->remote_mps;
1582 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001583
1584 while (len > 0) {
1585 size_t buflen;
1586
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001587 if (len > chan->remote_mps) {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001588 control = L2CAP_SDU_CONTINUE;
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001589 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001590 } else {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001591 control = L2CAP_SDU_END;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001592 buflen = len;
1593 }
1594
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001595 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001596 if (IS_ERR(skb)) {
1597 skb_queue_purge(&sar_queue);
1598 return PTR_ERR(skb);
1599 }
1600
1601 __skb_queue_tail(&sar_queue, skb);
1602 len -= buflen;
1603 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001604 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001605 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1606 if (chan->tx_send_head == NULL)
1607 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001608
1609 return size;
1610}
1611
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001612int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
1613{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001614 struct sk_buff *skb;
1615 u16 control;
1616 int err;
1617
1618 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001619 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001620 skb = l2cap_create_connless_pdu(chan, msg, len);
1621 if (IS_ERR(skb))
1622 return PTR_ERR(skb);
1623
1624 l2cap_do_send(chan, skb);
1625 return len;
1626 }
1627
1628 switch (chan->mode) {
1629 case L2CAP_MODE_BASIC:
1630 /* Check outgoing MTU */
1631 if (len > chan->omtu)
1632 return -EMSGSIZE;
1633
1634 /* Create a basic PDU */
1635 skb = l2cap_create_basic_pdu(chan, msg, len);
1636 if (IS_ERR(skb))
1637 return PTR_ERR(skb);
1638
1639 l2cap_do_send(chan, skb);
1640 err = len;
1641 break;
1642
1643 case L2CAP_MODE_ERTM:
1644 case L2CAP_MODE_STREAMING:
1645 /* Entire SDU fits into one PDU */
1646 if (len <= chan->remote_mps) {
1647 control = L2CAP_SDU_UNSEGMENTED;
1648 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1649 0);
1650 if (IS_ERR(skb))
1651 return PTR_ERR(skb);
1652
1653 __skb_queue_tail(&chan->tx_q, skb);
1654
1655 if (chan->tx_send_head == NULL)
1656 chan->tx_send_head = skb;
1657
1658 } else {
1659 /* Segment SDU into multiples PDUs */
1660 err = l2cap_sar_segment_sdu(chan, msg, len);
1661 if (err < 0)
1662 return err;
1663 }
1664
1665 if (chan->mode == L2CAP_MODE_STREAMING) {
1666 l2cap_streaming_send(chan);
1667 err = len;
1668 break;
1669 }
1670
1671 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
1672 (chan->conn_state & L2CAP_CONN_WAIT_F)) {
1673 err = len;
1674 break;
1675 }
1676
1677 err = l2cap_ertm_send(chan);
1678 if (err >= 0)
1679 err = len;
1680
1681 break;
1682
1683 default:
1684 BT_DBG("bad state %1.1x", chan->mode);
1685 err = -EBADFD;
1686 }
1687
1688 return err;
1689}
1690
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691/* Copy frame to all raw sockets on that connection */
1692static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1693{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001694 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001695 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 BT_DBG("conn %p", conn);
1698
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001699 read_lock(&conn->chan_lock);
1700 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001701 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001702 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 continue;
1704
1705 /* Don't send frame to the socket it came from */
1706 if (skb->sk == sk)
1707 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001708 nskb = skb_clone(skb, GFP_ATOMIC);
1709 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710 continue;
1711
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001712 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 kfree_skb(nskb);
1714 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001715 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716}
1717
1718/* ---- L2CAP signalling commands ---- */
1719static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1720 u8 code, u8 ident, u16 dlen, void *data)
1721{
1722 struct sk_buff *skb, **frag;
1723 struct l2cap_cmd_hdr *cmd;
1724 struct l2cap_hdr *lh;
1725 int len, count;
1726
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001727 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1728 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729
1730 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1731 count = min_t(unsigned int, conn->mtu, len);
1732
1733 skb = bt_skb_alloc(count, GFP_ATOMIC);
1734 if (!skb)
1735 return NULL;
1736
1737 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001738 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001739
1740 if (conn->hcon->type == LE_LINK)
1741 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1742 else
1743 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
1745 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1746 cmd->code = code;
1747 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001748 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749
1750 if (dlen) {
1751 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1752 memcpy(skb_put(skb, count), data, count);
1753 data += count;
1754 }
1755
1756 len -= skb->len;
1757
1758 /* Continuation fragments (no L2CAP header) */
1759 frag = &skb_shinfo(skb)->frag_list;
1760 while (len) {
1761 count = min_t(unsigned int, conn->mtu, len);
1762
1763 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1764 if (!*frag)
1765 goto fail;
1766
1767 memcpy(skb_put(*frag, count), data, count);
1768
1769 len -= count;
1770 data += count;
1771
1772 frag = &(*frag)->next;
1773 }
1774
1775 return skb;
1776
1777fail:
1778 kfree_skb(skb);
1779 return NULL;
1780}
1781
1782static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1783{
1784 struct l2cap_conf_opt *opt = *ptr;
1785 int len;
1786
1787 len = L2CAP_CONF_OPT_SIZE + opt->len;
1788 *ptr += len;
1789
1790 *type = opt->type;
1791 *olen = opt->len;
1792
1793 switch (opt->len) {
1794 case 1:
1795 *val = *((u8 *) opt->val);
1796 break;
1797
1798 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001799 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 break;
1801
1802 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001803 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 break;
1805
1806 default:
1807 *val = (unsigned long) opt->val;
1808 break;
1809 }
1810
1811 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1812 return len;
1813}
1814
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1816{
1817 struct l2cap_conf_opt *opt = *ptr;
1818
1819 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1820
1821 opt->type = type;
1822 opt->len = len;
1823
1824 switch (len) {
1825 case 1:
1826 *((u8 *) opt->val) = val;
1827 break;
1828
1829 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001830 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 break;
1832
1833 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001834 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 break;
1836
1837 default:
1838 memcpy(opt->val, (void *) val, len);
1839 break;
1840 }
1841
1842 *ptr += L2CAP_CONF_OPT_SIZE + len;
1843}
1844
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001845static void l2cap_ack_timeout(unsigned long arg)
1846{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001847 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001848
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001849 bh_lock_sock(chan->sk);
1850 l2cap_send_ack(chan);
1851 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001852}
1853
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001854static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001855{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001856 struct sock *sk = chan->sk;
1857
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001858 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001859 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001860 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001861 chan->num_acked = 0;
1862 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001863
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001864 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1865 (unsigned long) chan);
1866 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1867 (unsigned long) chan);
1868 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001869
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001870 skb_queue_head_init(&chan->srej_q);
1871 skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001872
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001873 INIT_LIST_HEAD(&chan->srej_l);
1874
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03001875 INIT_WORK(&chan->busy_work, l2cap_busy_work);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001876
1877 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001878}
1879
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001880static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1881{
1882 switch (mode) {
1883 case L2CAP_MODE_STREAMING:
1884 case L2CAP_MODE_ERTM:
1885 if (l2cap_mode_supported(mode, remote_feat_mask))
1886 return mode;
1887 /* fall through */
1888 default:
1889 return L2CAP_MODE_BASIC;
1890 }
1891}
1892
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03001893static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001896 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 void *ptr = req->data;
1898
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001899 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001901 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001902 goto done;
1903
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001904 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001905 case L2CAP_MODE_STREAMING:
1906 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001907 if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001908 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001909
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03001910 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001911 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001912 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001913 break;
1914 }
1915
1916done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001917 if (chan->imtu != L2CAP_DEFAULT_MTU)
1918 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02001919
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001920 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001921 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001922 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
1923 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001924 break;
1925
Gustavo F. Padovan62547752010-06-08 20:05:31 -03001926 rfc.mode = L2CAP_MODE_BASIC;
1927 rfc.txwin_size = 0;
1928 rfc.max_transmit = 0;
1929 rfc.retrans_timeout = 0;
1930 rfc.monitor_timeout = 0;
1931 rfc.max_pdu_size = 0;
1932
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001933 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1934 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001935 break;
1936
1937 case L2CAP_MODE_ERTM:
1938 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001939 rfc.txwin_size = chan->tx_win;
1940 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001941 rfc.retrans_timeout = 0;
1942 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001943 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001944 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1945 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001946
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001947 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1948 (unsigned long) &rfc);
1949
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001950 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001951 break;
1952
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001953 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001954 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001955 chan->fcs = L2CAP_FCS_NONE;
1956 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001957 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001958 break;
1959
1960 case L2CAP_MODE_STREAMING:
1961 rfc.mode = L2CAP_MODE_STREAMING;
1962 rfc.txwin_size = 0;
1963 rfc.max_transmit = 0;
1964 rfc.retrans_timeout = 0;
1965 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001966 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001967 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1968 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001969
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001970 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1971 (unsigned long) &rfc);
1972
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001973 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001974 break;
1975
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001976 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001977 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001978 chan->fcs = L2CAP_FCS_NONE;
1979 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001980 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001981 break;
1982 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001984 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001985 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986
1987 return ptr - data;
1988}
1989
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001990static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001992 struct l2cap_conf_rsp *rsp = data;
1993 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001994 void *req = chan->conf_req;
1995 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001996 int type, hint, olen;
1997 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02001998 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Marcel Holtmann861d6882007-10-20 13:37:06 +02001999 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002000 u16 result = L2CAP_CONF_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002002 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002003
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002004 while (len >= L2CAP_CONF_OPT_SIZE) {
2005 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002007 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002008 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002009
2010 switch (type) {
2011 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002012 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002013 break;
2014
2015 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002016 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002017 break;
2018
2019 case L2CAP_CONF_QOS:
2020 break;
2021
Marcel Holtmann6464f352007-10-20 13:39:51 +02002022 case L2CAP_CONF_RFC:
2023 if (olen == sizeof(rfc))
2024 memcpy(&rfc, (void *) val, olen);
2025 break;
2026
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002027 case L2CAP_CONF_FCS:
2028 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002029 chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002030
2031 break;
2032
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002033 default:
2034 if (hint)
2035 break;
2036
2037 result = L2CAP_CONF_UNKNOWN;
2038 *((u8 *) ptr++) = type;
2039 break;
2040 }
2041 }
2042
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002043 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002044 goto done;
2045
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002046 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002047 case L2CAP_MODE_STREAMING:
2048 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002049 if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002050 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002051 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002052 break;
2053 }
2054
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002055 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002056 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002057
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002058 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002059 }
2060
2061done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002062 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002063 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002064 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002065
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002066 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002067 return -ECONNREFUSED;
2068
2069 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2070 sizeof(rfc), (unsigned long) &rfc);
2071 }
2072
2073
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002074 if (result == L2CAP_CONF_SUCCESS) {
2075 /* Configure output options and let the other side know
2076 * which ones we don't like. */
2077
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002078 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2079 result = L2CAP_CONF_UNACCEPT;
2080 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002081 chan->omtu = mtu;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002082 chan->conf_state |= L2CAP_CONF_MTU_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002083 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002084 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002085
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002086 switch (rfc.mode) {
2087 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002088 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002089 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002090 break;
2091
2092 case L2CAP_MODE_ERTM:
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002093 chan->remote_tx_win = rfc.txwin_size;
2094 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002095
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002096 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2097 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002098
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002099 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002100
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002101 rfc.retrans_timeout =
2102 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2103 rfc.monitor_timeout =
2104 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002105
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002106 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002107
2108 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2109 sizeof(rfc), (unsigned long) &rfc);
2110
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002111 break;
2112
2113 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002114 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2115 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002116
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002117 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002118
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002119 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002120
2121 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2122 sizeof(rfc), (unsigned long) &rfc);
2123
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002124 break;
2125
2126 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002127 result = L2CAP_CONF_UNACCEPT;
2128
2129 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002130 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002131 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002132
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002133 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002134 chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002135 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002136 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002137 rsp->result = cpu_to_le16(result);
2138 rsp->flags = cpu_to_le16(0x0000);
2139
2140 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141}
2142
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002143static 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 -03002144{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002145 struct l2cap_conf_req *req = data;
2146 void *ptr = req->data;
2147 int type, olen;
2148 unsigned long val;
2149 struct l2cap_conf_rfc rfc;
2150
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002151 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002152
2153 while (len >= L2CAP_CONF_OPT_SIZE) {
2154 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2155
2156 switch (type) {
2157 case L2CAP_CONF_MTU:
2158 if (val < L2CAP_DEFAULT_MIN_MTU) {
2159 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002160 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002161 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002162 chan->imtu = val;
2163 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002164 break;
2165
2166 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002167 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002168 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002169 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002170 break;
2171
2172 case L2CAP_CONF_RFC:
2173 if (olen == sizeof(rfc))
2174 memcpy(&rfc, (void *)val, olen);
2175
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002176 if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002177 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002178 return -ECONNREFUSED;
2179
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002180 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002181
2182 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2183 sizeof(rfc), (unsigned long) &rfc);
2184 break;
2185 }
2186 }
2187
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002188 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002189 return -ECONNREFUSED;
2190
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002191 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002192
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002193 if (*result == L2CAP_CONF_SUCCESS) {
2194 switch (rfc.mode) {
2195 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002196 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2197 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2198 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002199 break;
2200 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002201 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002202 }
2203 }
2204
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002205 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002206 req->flags = cpu_to_le16(0x0000);
2207
2208 return ptr - data;
2209}
2210
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002211static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212{
2213 struct l2cap_conf_rsp *rsp = data;
2214 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002216 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002218 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002219 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002220 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221
2222 return ptr - data;
2223}
2224
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002225void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002226{
2227 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002228 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002229 u8 buf[128];
2230
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002231 rsp.scid = cpu_to_le16(chan->dcid);
2232 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002233 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2234 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2235 l2cap_send_cmd(conn, chan->ident,
2236 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2237
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002238 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002239 return;
2240
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002241 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002242 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2243 l2cap_build_conf_req(chan, buf), buf);
2244 chan->num_conf_req++;
2245}
2246
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002247static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002248{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002249 int type, olen;
2250 unsigned long val;
2251 struct l2cap_conf_rfc rfc;
2252
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002253 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002254
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002255 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002256 return;
2257
2258 while (len >= L2CAP_CONF_OPT_SIZE) {
2259 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2260
2261 switch (type) {
2262 case L2CAP_CONF_RFC:
2263 if (olen == sizeof(rfc))
2264 memcpy(&rfc, (void *)val, olen);
2265 goto done;
2266 }
2267 }
2268
2269done:
2270 switch (rfc.mode) {
2271 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002272 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2273 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2274 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002275 break;
2276 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002277 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002278 }
2279}
2280
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002281static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2282{
2283 struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
2284
2285 if (rej->reason != 0x0000)
2286 return 0;
2287
2288 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2289 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002290 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002291
2292 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002293 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002294
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002295 l2cap_conn_start(conn);
2296 }
2297
2298 return 0;
2299}
2300
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2302{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2304 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002305 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002306 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002307 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308
2309 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002310 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002311
2312 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2313
2314 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002315 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2316 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 result = L2CAP_CR_BAD_PSM;
2318 goto sendresp;
2319 }
2320
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002321 parent = pchan->sk;
2322
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002323 bh_lock_sock(parent);
2324
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002325 /* Check if the ACL is secure enough (if not SDP) */
2326 if (psm != cpu_to_le16(0x0001) &&
2327 !hci_conn_check_link_mode(conn->hcon)) {
Marcel Holtmann2950f212009-02-12 14:02:50 +01002328 conn->disc_reason = 0x05;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002329 result = L2CAP_CR_SEC_BLOCK;
2330 goto response;
2331 }
2332
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 result = L2CAP_CR_NO_MEM;
2334
2335 /* Check for backlog size */
2336 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002337 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 goto response;
2339 }
2340
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002341 chan = pchan->ops->new_connection(pchan->data);
2342 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343 goto response;
2344
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002345 sk = chan->sk;
2346
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002347 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
2349 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002350 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2351 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002353 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 goto response;
2355 }
2356
2357 hci_conn_hold(conn->hcon);
2358
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 bacpy(&bt_sk(sk)->src, conn->src);
2360 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002361 chan->psm = psm;
2362 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002364 bt_accept_enqueue(parent, sk);
2365
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002366 __l2cap_chan_add(conn, chan);
2367
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002368 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002370 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002372 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
Marcel Holtmann984947d2009-02-06 23:35:19 +01002374 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03002375 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002376 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002377 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002378 result = L2CAP_CR_PEND;
2379 status = L2CAP_CS_AUTHOR_PEND;
2380 parent->sk_data_ready(parent, 0);
2381 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002382 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002383 result = L2CAP_CR_SUCCESS;
2384 status = L2CAP_CS_NO_INFO;
2385 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002386 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002387 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002388 result = L2CAP_CR_PEND;
2389 status = L2CAP_CS_AUTHEN_PEND;
2390 }
2391 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002392 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002393 result = L2CAP_CR_PEND;
2394 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 }
2396
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002397 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002398
2399response:
2400 bh_unlock_sock(parent);
2401
2402sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002403 rsp.scid = cpu_to_le16(scid);
2404 rsp.dcid = cpu_to_le16(dcid);
2405 rsp.result = cpu_to_le16(result);
2406 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002408
2409 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2410 struct l2cap_info_req info;
2411 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2412
2413 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2414 conn->info_ident = l2cap_get_ident(conn);
2415
2416 mod_timer(&conn->info_timer, jiffies +
2417 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2418
2419 l2cap_send_cmd(conn, conn->info_ident,
2420 L2CAP_INFO_REQ, sizeof(info), &info);
2421 }
2422
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002423 if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002424 result == L2CAP_CR_SUCCESS) {
2425 u8 buf[128];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002426 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002427 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002428 l2cap_build_conf_req(chan, buf), buf);
2429 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002430 }
2431
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 return 0;
2433}
2434
2435static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2436{
2437 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2438 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002439 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 struct sock *sk;
2441 u8 req[128];
2442
2443 scid = __le16_to_cpu(rsp->scid);
2444 dcid = __le16_to_cpu(rsp->dcid);
2445 result = __le16_to_cpu(rsp->result);
2446 status = __le16_to_cpu(rsp->status);
2447
2448 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2449
2450 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002451 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002452 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002453 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002455 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002456 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002457 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458 }
2459
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002460 sk = chan->sk;
2461
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 switch (result) {
2463 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002464 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002465 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002466 chan->dcid = dcid;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002467 chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002468
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002469 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002470 break;
2471
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002472 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002473
Linus Torvalds1da177e2005-04-16 15:20:36 -07002474 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002475 l2cap_build_conf_req(chan, req), req);
2476 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 break;
2478
2479 case L2CAP_CR_PEND:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002480 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 break;
2482
2483 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002484 /* don't delete l2cap channel if sk is owned by user */
2485 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002486 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002487 __clear_chan_timer(chan);
2488 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002489 break;
2490 }
2491
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002492 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 break;
2494 }
2495
2496 bh_unlock_sock(sk);
2497 return 0;
2498}
2499
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002500static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002501{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002502 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
2503
Mat Martineau8c462b62010-08-24 15:35:42 -07002504 /* FCS is enabled only in ERTM or streaming mode, if one or both
2505 * sides request it.
2506 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002507 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002508 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002509 else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002510 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002511}
2512
Al Viro88219a02007-07-29 00:17:25 -07002513static 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 -07002514{
2515 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2516 u16 dcid, flags;
2517 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002518 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002520 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521
2522 dcid = __le16_to_cpu(req->dcid);
2523 flags = __le16_to_cpu(req->flags);
2524
2525 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2526
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002527 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002528 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 return -ENOENT;
2530
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002531 sk = chan->sk;
2532
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002533 if (chan->state != BT_CONFIG) {
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002534 struct l2cap_cmd_rej rej;
2535
2536 rej.reason = cpu_to_le16(0x0002);
2537 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2538 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002539 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002540 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002541
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002542 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002543 len = cmd_len - sizeof(*req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002544 if (chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002545 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002546 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002547 L2CAP_CONF_REJECT, flags), rsp);
2548 goto unlock;
2549 }
2550
2551 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002552 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2553 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554
2555 if (flags & 0x0001) {
2556 /* Incomplete config. Send empty response. */
2557 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002558 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002559 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 goto unlock;
2561 }
2562
2563 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002564 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002565 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002566 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002570 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002571 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002572
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002573 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002574 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002575
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002576 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002577 goto unlock;
2578
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002579 if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002580 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002581
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002582 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002583
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002584 chan->next_tx_seq = 0;
2585 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002586 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002587 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002588 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002589
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002591 goto unlock;
2592 }
2593
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002594 if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002595 u8 buf[64];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002596 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002598 l2cap_build_conf_req(chan, buf), buf);
2599 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 }
2601
2602unlock:
2603 bh_unlock_sock(sk);
2604 return 0;
2605}
2606
2607static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2608{
2609 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2610 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002611 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002613 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615 scid = __le16_to_cpu(rsp->scid);
2616 flags = __le16_to_cpu(rsp->flags);
2617 result = __le16_to_cpu(rsp->result);
2618
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002619 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2620 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002622 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002623 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 return 0;
2625
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002626 sk = chan->sk;
2627
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 switch (result) {
2629 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002630 l2cap_conf_rfc_get(chan, rsp->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 break;
2632
2633 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002634 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002635 char req[64];
2636
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002637 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002638 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002639 goto done;
2640 }
2641
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002642 /* throw out any old stored conf requests */
2643 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002644 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2645 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002646 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002647 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002648 goto done;
2649 }
2650
2651 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2652 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002653 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002654 if (result != L2CAP_CONF_SUCCESS)
2655 goto done;
2656 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 }
2658
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002659 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002660 sk->sk_err = ECONNRESET;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002661 __set_chan_timer(chan, HZ * 5);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002662 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663 goto done;
2664 }
2665
2666 if (flags & 0x01)
2667 goto done;
2668
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002669 chan->conf_state |= L2CAP_CONF_INPUT_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002671 if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002672 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002673
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002674 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002675 chan->next_tx_seq = 0;
2676 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002677 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002678 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002679 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002680
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 l2cap_chan_ready(sk);
2682 }
2683
2684done:
2685 bh_unlock_sock(sk);
2686 return 0;
2687}
2688
2689static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2690{
2691 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2692 struct l2cap_disconn_rsp rsp;
2693 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002694 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 struct sock *sk;
2696
2697 scid = __le16_to_cpu(req->scid);
2698 dcid = __le16_to_cpu(req->dcid);
2699
2700 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2701
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002702 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002703 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 return 0;
2705
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002706 sk = chan->sk;
2707
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002708 rsp.dcid = cpu_to_le16(chan->scid);
2709 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2711
2712 sk->sk_shutdown = SHUTDOWN_MASK;
2713
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002714 /* don't delete l2cap channel if sk is owned by user */
2715 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002716 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002717 __clear_chan_timer(chan);
2718 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002719 bh_unlock_sock(sk);
2720 return 0;
2721 }
2722
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002723 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 bh_unlock_sock(sk);
2725
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002726 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 return 0;
2728}
2729
2730static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2731{
2732 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
2733 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002734 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 struct sock *sk;
2736
2737 scid = __le16_to_cpu(rsp->scid);
2738 dcid = __le16_to_cpu(rsp->dcid);
2739
2740 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
2741
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002742 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002743 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 return 0;
2745
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002746 sk = chan->sk;
2747
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002748 /* don't delete l2cap channel if sk is owned by user */
2749 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002750 l2cap_state_change(chan,BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002751 __clear_chan_timer(chan);
2752 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002753 bh_unlock_sock(sk);
2754 return 0;
2755 }
2756
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002757 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 bh_unlock_sock(sk);
2759
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002760 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 return 0;
2762}
2763
2764static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2765{
2766 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 u16 type;
2768
2769 type = __le16_to_cpu(req->type);
2770
2771 BT_DBG("type 0x%4.4x", type);
2772
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002773 if (type == L2CAP_IT_FEAT_MASK) {
2774 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07002775 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002776 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2777 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2778 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03002779 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002780 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
2781 | L2CAP_FEAT_FCS;
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03002782 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002783 l2cap_send_cmd(conn, cmd->ident,
2784 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002785 } else if (type == L2CAP_IT_FIXED_CHAN) {
2786 u8 buf[12];
2787 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2788 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2789 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
2790 memcpy(buf + 4, l2cap_fixed_chan, 8);
2791 l2cap_send_cmd(conn, cmd->ident,
2792 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002793 } else {
2794 struct l2cap_info_rsp rsp;
2795 rsp.type = cpu_to_le16(type);
2796 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
2797 l2cap_send_cmd(conn, cmd->ident,
2798 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
2799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
2801 return 0;
2802}
2803
2804static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2805{
2806 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
2807 u16 type, result;
2808
2809 type = __le16_to_cpu(rsp->type);
2810 result = __le16_to_cpu(rsp->result);
2811
2812 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
2813
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02002814 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
2815 if (cmd->ident != conn->info_ident ||
2816 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
2817 return 0;
2818
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002819 del_timer(&conn->info_timer);
2820
Ville Tervoadb08ed2010-08-04 09:43:33 +03002821 if (result != L2CAP_IR_SUCCESS) {
2822 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2823 conn->info_ident = 0;
2824
2825 l2cap_conn_start(conn);
2826
2827 return 0;
2828 }
2829
Marcel Holtmann984947d2009-02-06 23:35:19 +01002830 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07002831 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002832
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002833 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002834 struct l2cap_info_req req;
2835 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2836
2837 conn->info_ident = l2cap_get_ident(conn);
2838
2839 l2cap_send_cmd(conn, conn->info_ident,
2840 L2CAP_INFO_REQ, sizeof(req), &req);
2841 } else {
2842 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2843 conn->info_ident = 0;
2844
2845 l2cap_conn_start(conn);
2846 }
2847 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01002848 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002849 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002850
2851 l2cap_conn_start(conn);
2852 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002853
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 return 0;
2855}
2856
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002857static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02002858 u16 to_multiplier)
2859{
2860 u16 max_latency;
2861
2862 if (min > max || min < 6 || max > 3200)
2863 return -EINVAL;
2864
2865 if (to_multiplier < 10 || to_multiplier > 3200)
2866 return -EINVAL;
2867
2868 if (max >= to_multiplier * 8)
2869 return -EINVAL;
2870
2871 max_latency = (to_multiplier * 8 / max) - 1;
2872 if (latency > 499 || latency > max_latency)
2873 return -EINVAL;
2874
2875 return 0;
2876}
2877
2878static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
2879 struct l2cap_cmd_hdr *cmd, u8 *data)
2880{
2881 struct hci_conn *hcon = conn->hcon;
2882 struct l2cap_conn_param_update_req *req;
2883 struct l2cap_conn_param_update_rsp rsp;
2884 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002885 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02002886
2887 if (!(hcon->link_mode & HCI_LM_MASTER))
2888 return -EINVAL;
2889
2890 cmd_len = __le16_to_cpu(cmd->len);
2891 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
2892 return -EPROTO;
2893
2894 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002895 min = __le16_to_cpu(req->min);
2896 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02002897 latency = __le16_to_cpu(req->latency);
2898 to_multiplier = __le16_to_cpu(req->to_multiplier);
2899
2900 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
2901 min, max, latency, to_multiplier);
2902
2903 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002904
2905 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
2906 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02002907 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
2908 else
2909 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
2910
2911 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
2912 sizeof(rsp), &rsp);
2913
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002914 if (!err)
2915 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
2916
Claudio Takahaside731152011-02-11 19:28:55 -02002917 return 0;
2918}
2919
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002920static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
2921 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
2922{
2923 int err = 0;
2924
2925 switch (cmd->code) {
2926 case L2CAP_COMMAND_REJ:
2927 l2cap_command_rej(conn, cmd, data);
2928 break;
2929
2930 case L2CAP_CONN_REQ:
2931 err = l2cap_connect_req(conn, cmd, data);
2932 break;
2933
2934 case L2CAP_CONN_RSP:
2935 err = l2cap_connect_rsp(conn, cmd, data);
2936 break;
2937
2938 case L2CAP_CONF_REQ:
2939 err = l2cap_config_req(conn, cmd, cmd_len, data);
2940 break;
2941
2942 case L2CAP_CONF_RSP:
2943 err = l2cap_config_rsp(conn, cmd, data);
2944 break;
2945
2946 case L2CAP_DISCONN_REQ:
2947 err = l2cap_disconnect_req(conn, cmd, data);
2948 break;
2949
2950 case L2CAP_DISCONN_RSP:
2951 err = l2cap_disconnect_rsp(conn, cmd, data);
2952 break;
2953
2954 case L2CAP_ECHO_REQ:
2955 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
2956 break;
2957
2958 case L2CAP_ECHO_RSP:
2959 break;
2960
2961 case L2CAP_INFO_REQ:
2962 err = l2cap_information_req(conn, cmd, data);
2963 break;
2964
2965 case L2CAP_INFO_RSP:
2966 err = l2cap_information_rsp(conn, cmd, data);
2967 break;
2968
2969 default:
2970 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
2971 err = -EINVAL;
2972 break;
2973 }
2974
2975 return err;
2976}
2977
2978static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
2979 struct l2cap_cmd_hdr *cmd, u8 *data)
2980{
2981 switch (cmd->code) {
2982 case L2CAP_COMMAND_REJ:
2983 return 0;
2984
2985 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02002986 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002987
2988 case L2CAP_CONN_PARAM_UPDATE_RSP:
2989 return 0;
2990
2991 default:
2992 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
2993 return -EINVAL;
2994 }
2995}
2996
2997static inline void l2cap_sig_channel(struct l2cap_conn *conn,
2998 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999{
3000 u8 *data = skb->data;
3001 int len = skb->len;
3002 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003003 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004
3005 l2cap_raw_recv(conn, skb);
3006
3007 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003008 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003009 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3010 data += L2CAP_CMD_HDR_SIZE;
3011 len -= L2CAP_CMD_HDR_SIZE;
3012
Al Viro88219a02007-07-29 00:17:25 -07003013 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014
Al Viro88219a02007-07-29 00:17:25 -07003015 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 -07003016
Al Viro88219a02007-07-29 00:17:25 -07003017 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003018 BT_DBG("corrupted command");
3019 break;
3020 }
3021
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003022 if (conn->hcon->type == LE_LINK)
3023 err = l2cap_le_sig_cmd(conn, &cmd, data);
3024 else
3025 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026
3027 if (err) {
3028 struct l2cap_cmd_rej rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003029
3030 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031
3032 /* FIXME: Map err to a valid reason */
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07003033 rej.reason = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3035 }
3036
Al Viro88219a02007-07-29 00:17:25 -07003037 data += cmd_len;
3038 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 }
3040
3041 kfree_skb(skb);
3042}
3043
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003044static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003045{
3046 u16 our_fcs, rcv_fcs;
3047 int hdr_size = L2CAP_HDR_SIZE + 2;
3048
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003049 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003050 skb_trim(skb, skb->len - 2);
3051 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3052 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3053
3054 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003055 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003056 }
3057 return 0;
3058}
3059
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003060static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003061{
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003062 u16 control = 0;
3063
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003064 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003065
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003066 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003067
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003068 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan64988862010-05-10 14:54:14 -03003069 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003070 l2cap_send_sframe(chan, control);
3071 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003072 }
3073
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003074 if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
3075 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003076
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003077 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003078
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003079 if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003080 chan->frames_sent == 0) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003081 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003082 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003083 }
3084}
3085
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003086static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003087{
3088 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003089 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003090
3091 bt_cb(skb)->tx_seq = tx_seq;
3092 bt_cb(skb)->sar = sar;
3093
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003094 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003095 if (!next_skb) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003096 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003097 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003098 }
3099
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003100 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003101 if (tx_seq_offset < 0)
3102 tx_seq_offset += 64;
3103
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003104 do {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003105 if (bt_cb(next_skb)->tx_seq == tx_seq)
3106 return -EINVAL;
3107
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003108 next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003109 chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003110 if (next_tx_seq_offset < 0)
3111 next_tx_seq_offset += 64;
3112
3113 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003114 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003115 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003116 }
3117
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003118 if (skb_queue_is_last(&chan->srej_q, next_skb))
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003119 break;
3120
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003121 } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003122
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003123 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003124
3125 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003126}
3127
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003128static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003129{
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003130 struct sk_buff *_skb;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003131 int err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003132
3133 switch (control & L2CAP_CTRL_SAR) {
3134 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003135 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003136 goto drop;
3137
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003138 return chan->ops->recv(chan->data, skb);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003139
3140 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003141 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003142 goto drop;
3143
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003144 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003145
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003146 if (chan->sdu_len > chan->imtu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003147 goto disconnect;
3148
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003149 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3150 if (!chan->sdu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003151 return -ENOMEM;
3152
3153 /* pull sdu_len bytes only after alloc, because of Local Busy
3154 * condition we have to be sure that this will be executed
3155 * only once, i.e., when alloc does not fail */
3156 skb_pull(skb, 2);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003157
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003158 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003159
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003160 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003161 chan->partial_sdu_len = skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003162 break;
3163
3164 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003165 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003166 goto disconnect;
3167
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003168 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003169 goto disconnect;
3170
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003171 chan->partial_sdu_len += skb->len;
3172 if (chan->partial_sdu_len > chan->sdu_len)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003173 goto drop;
3174
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003175 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003176
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003177 break;
3178
3179 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003180 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003181 goto disconnect;
3182
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003183 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003184 goto disconnect;
3185
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003186 if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003187 chan->partial_sdu_len += skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003188
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003189 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003190 goto drop;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003191
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003192 if (chan->partial_sdu_len != chan->sdu_len)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003193 goto drop;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003194
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003195 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003196 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003197
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003198 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003199 if (!_skb) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003200 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003201 return -ENOMEM;
3202 }
3203
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003204 err = chan->ops->recv(chan->data, _skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003205 if (err < 0) {
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003206 kfree_skb(_skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003207 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003208 return err;
3209 }
3210
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003211 chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
3212 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003213
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003214 kfree_skb(chan->sdu);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003215 break;
3216 }
3217
3218 kfree_skb(skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003219 return 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003220
3221drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003222 kfree_skb(chan->sdu);
3223 chan->sdu = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003224
3225disconnect:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003226 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003227 kfree_skb(skb);
3228 return 0;
3229}
3230
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003231static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003232{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003233 struct sk_buff *skb;
3234 u16 control;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003235 int err;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003236
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003237 while ((skb = skb_dequeue(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003238 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003239 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003240 if (err < 0) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003241 skb_queue_head(&chan->busy_q, skb);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003242 return -EBUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003243 }
3244
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003245 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003246 }
3247
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003248 if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003249 goto done;
3250
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003251 control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003252 control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003253 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003254 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003255
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003256 __clear_retrans_timer(chan);
3257 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003258
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003259 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003260
3261done:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003262 chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
3263 chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003264
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003265 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003266
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003267 return 0;
3268}
3269
3270static void l2cap_busy_work(struct work_struct *work)
3271{
3272 DECLARE_WAITQUEUE(wait, current);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003273 struct l2cap_chan *chan =
3274 container_of(work, struct l2cap_chan, busy_work);
3275 struct sock *sk = chan->sk;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003276 int n_tries = 0, timeo = HZ/5, err;
3277 struct sk_buff *skb;
3278
3279 lock_sock(sk);
3280
3281 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003282 while ((skb = skb_peek(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003283 set_current_state(TASK_INTERRUPTIBLE);
3284
3285 if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
3286 err = -EBUSY;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003287 l2cap_send_disconn_req(chan->conn, chan, EBUSY);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003288 break;
3289 }
3290
3291 if (!timeo)
3292 timeo = HZ/5;
3293
3294 if (signal_pending(current)) {
3295 err = sock_intr_errno(timeo);
3296 break;
3297 }
3298
3299 release_sock(sk);
3300 timeo = schedule_timeout(timeo);
3301 lock_sock(sk);
3302
3303 err = sock_error(sk);
3304 if (err)
3305 break;
3306
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003307 if (l2cap_try_push_rx_skb(chan) == 0)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003308 break;
3309 }
3310
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003311 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02003312 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003313
3314 release_sock(sk);
3315}
3316
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003317static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003318{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003319 int sctrl, err;
3320
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003321 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003322 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003323 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003324 return l2cap_try_push_rx_skb(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003325
3326
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003327 }
3328
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003329 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003330 if (err >= 0) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003331 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003332 return err;
3333 }
3334
3335 /* Busy Condition */
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003336 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003337
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003338 chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003339 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003340 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003341
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003342 sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003343 sctrl |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003344 l2cap_send_sframe(chan, sctrl);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003345
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003346 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003347
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003348 __clear_ack_timer(chan);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003349
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003350 queue_work(_busy_wq, &chan->busy_work);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003351
3352 return err;
3353}
3354
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003355static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003356{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003357 struct sk_buff *_skb;
3358 int err = -EINVAL;
3359
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003360 /*
3361 * TODO: We have to notify the userland if some data is lost with the
3362 * Streaming Mode.
3363 */
3364
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003365 switch (control & L2CAP_CTRL_SAR) {
3366 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003367 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003368 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003369 break;
3370 }
3371
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003372 err = chan->ops->recv(chan->data, skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003373 if (!err)
3374 return 0;
3375
3376 break;
3377
3378 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003379 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003380 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003381 break;
3382 }
3383
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003384 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003385 skb_pull(skb, 2);
3386
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003387 if (chan->sdu_len > chan->imtu) {
Gustavo F. Padovan052897c2010-05-01 16:15:40 -03003388 err = -EMSGSIZE;
3389 break;
3390 }
3391
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003392 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3393 if (!chan->sdu) {
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003394 err = -ENOMEM;
3395 break;
3396 }
3397
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003398 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003399
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003400 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003401 chan->partial_sdu_len = skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003402 err = 0;
3403 break;
3404
3405 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003406 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003407 break;
3408
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003409 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003410
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003411 chan->partial_sdu_len += skb->len;
3412 if (chan->partial_sdu_len > chan->sdu_len)
3413 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003414 else
3415 err = 0;
3416
3417 break;
3418
3419 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003420 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003421 break;
3422
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003423 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003424
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003425 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003426 chan->partial_sdu_len += skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003427
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003428 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003429 goto drop;
3430
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003431 if (chan->partial_sdu_len == chan->sdu_len) {
3432 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003433 err = chan->ops->recv(chan->data, _skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003434 if (err < 0)
3435 kfree_skb(_skb);
3436 }
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003437 err = 0;
3438
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003439drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003440 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003441 break;
3442 }
3443
3444 kfree_skb(skb);
3445 return err;
3446}
3447
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003448static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003449{
3450 struct sk_buff *skb;
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003451 u16 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003452
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003453 while ((skb = skb_peek(&chan->srej_q))) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003454 if (bt_cb(skb)->tx_seq != tx_seq)
3455 break;
3456
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003457 skb = skb_dequeue(&chan->srej_q);
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003458 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003459 l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003460 chan->buffer_seq_srej =
3461 (chan->buffer_seq_srej + 1) % 64;
Gustavo F. Padovan8ff50ec2010-05-10 19:34:11 -03003462 tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003463 }
3464}
3465
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003466static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003467{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003468 struct srej_list *l, *tmp;
3469 u16 control;
3470
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003471 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003472 if (l->tx_seq == tx_seq) {
3473 list_del(&l->list);
3474 kfree(l);
3475 return;
3476 }
3477 control = L2CAP_SUPER_SELECT_REJECT;
3478 control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003479 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003480 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003481 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003482 }
3483}
3484
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003485static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003486{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003487 struct srej_list *new;
3488 u16 control;
3489
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003490 while (tx_seq != chan->expected_tx_seq) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003491 control = L2CAP_SUPER_SELECT_REJECT;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003492 control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003493 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003494
3495 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003496 new->tx_seq = chan->expected_tx_seq;
3497 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003498 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003499 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003500 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003501}
3502
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003503static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003504{
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003505 u8 tx_seq = __get_txseq(rx_control);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003506 u8 req_seq = __get_reqseq(rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003507 u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003508 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003509 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003510 int err = 0;
3511
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003512 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
3513 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003514
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003515 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003516 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003517 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003518 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003519 __set_retrans_timer(chan);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003520 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003521 }
3522
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003523 chan->expected_ack_seq = req_seq;
3524 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003525
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003526 if (tx_seq == chan->expected_tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003527 goto expected;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003528
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003529 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003530 if (tx_seq_offset < 0)
3531 tx_seq_offset += 64;
3532
3533 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003534 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003535 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003536 goto drop;
3537 }
3538
Mat Martineaue6949282011-06-03 16:21:10 -07003539 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003540 goto drop;
3541
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003542 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003543 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003544
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003545 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003546 struct srej_list, list);
3547 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003548 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003549 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003550
3551 list_del(&first->list);
3552 kfree(first);
3553
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003554 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003555 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003556 chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
3557 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003558 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003559 }
3560 } else {
3561 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003562
3563 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003564 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003565 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003566
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003567 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003568 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003569 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003570 return 0;
3571 }
3572 }
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003573 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003574 }
3575 } else {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003576 expected_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003577 (chan->expected_tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003578 if (expected_tx_seq_offset < 0)
3579 expected_tx_seq_offset += 64;
3580
3581 /* duplicated tx_seq */
3582 if (tx_seq_offset < expected_tx_seq_offset)
3583 goto drop;
3584
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003585 chan->conn_state |= L2CAP_CONN_SREJ_SENT;
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003586
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003587 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003588
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003589 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003590 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003591
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003592 __skb_queue_head_init(&chan->srej_q);
3593 __skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003594 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003595
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003596 chan->conn_state |= L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003597
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003598 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003599
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003600 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003601 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003602 return 0;
3603
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003604expected:
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003605 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003606
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003607 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003608 bt_cb(skb)->tx_seq = tx_seq;
3609 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003610 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003611 return 0;
3612 }
3613
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003614 err = l2cap_push_rx_skb(chan, skb, rx_control);
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003615 if (err < 0)
3616 return 0;
3617
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003618 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003619 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3620 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003621 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003622 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003623 }
3624
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003625 __set_ack_timer(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003626
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003627 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3628 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003629 l2cap_send_ack(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003630
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003631 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003632
3633drop:
3634 kfree_skb(skb);
3635 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003636}
3637
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003638static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003639{
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003640 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003641 rx_control);
3642
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003643 chan->expected_ack_seq = __get_reqseq(rx_control);
3644 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003645
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003646 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003647 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3648 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
3649 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003650 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003651 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003652
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003653 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3654 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003655 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003656 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003657 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003658
3659 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003660 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003661
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003662 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3663 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003664 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003665 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003666
3667 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003668 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003669 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003670 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003671
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003672 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3673 if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
3674 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003675 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003676 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003677 }
3678}
3679
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003680static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003681{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003682 u8 tx_seq = __get_reqseq(rx_control);
3683
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003684 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003685
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003686 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003687
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003688 chan->expected_ack_seq = tx_seq;
3689 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003690
3691 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003692 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3693 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003694 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003695 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003696 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003697 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003698
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003699 if (chan->conn_state & L2CAP_CONN_WAIT_F)
3700 chan->conn_state |= L2CAP_CONN_REJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003701 }
3702}
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003703static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003704{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003705 u8 tx_seq = __get_reqseq(rx_control);
3706
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003707 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003708
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003709 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003710
3711 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003712 chan->expected_ack_seq = tx_seq;
3713 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003714
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003715 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3716 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003717
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003718 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003719
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003720 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003721 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003722 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003723 }
3724 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003725 if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003726 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003727 chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003728 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003729 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003730 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003731 l2cap_retransmit_one_frame(chan, tx_seq);
3732 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003733 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003734 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003735 }
3736 }
3737}
3738
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003739static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003740{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003741 u8 tx_seq = __get_reqseq(rx_control);
3742
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003743 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003744
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003745 chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003746 chan->expected_ack_seq = tx_seq;
3747 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003748
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003749 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003750 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003751
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003752 if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003753 __clear_retrans_timer(chan);
Gustavo F. Padovana2e12a22010-05-05 19:58:27 -03003754 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003755 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003756 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003757 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003758
3759 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003760 l2cap_send_srejtail(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003761 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003762 l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003763}
3764
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003765static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003766{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003767 BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003768
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003769 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003770 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003771 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003772 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003773 __set_retrans_timer(chan);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003774 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003775 }
3776
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003777 switch (rx_control & L2CAP_CTRL_SUPERVISE) {
3778 case L2CAP_SUPER_RCV_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003779 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003780 break;
3781
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003782 case L2CAP_SUPER_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003783 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003784 break;
3785
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003786 case L2CAP_SUPER_SELECT_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003787 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003788 break;
3789
3790 case L2CAP_SUPER_RCV_NOT_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003791 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003792 break;
3793 }
3794
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03003795 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003796 return 0;
3797}
3798
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003799static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
3800{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003801 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003802 u16 control;
3803 u8 req_seq;
3804 int len, next_tx_seq_offset, req_seq_offset;
3805
3806 control = get_unaligned_le16(skb->data);
3807 skb_pull(skb, 2);
3808 len = skb->len;
3809
3810 /*
3811 * We can just drop the corrupted I-frame here.
3812 * Receiver will miss it and start proper recovery
3813 * procedures and ask retransmission.
3814 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003815 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003816 goto drop;
3817
3818 if (__is_sar_start(control) && __is_iframe(control))
3819 len -= 2;
3820
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003821 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003822 len -= 2;
3823
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003824 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003825 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003826 goto drop;
3827 }
3828
3829 req_seq = __get_reqseq(control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003830 req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003831 if (req_seq_offset < 0)
3832 req_seq_offset += 64;
3833
3834 next_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003835 (chan->next_tx_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003836 if (next_tx_seq_offset < 0)
3837 next_tx_seq_offset += 64;
3838
3839 /* check for invalid req-seq */
3840 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003841 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003842 goto drop;
3843 }
3844
3845 if (__is_iframe(control)) {
3846 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003847 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003848 goto drop;
3849 }
3850
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003851 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003852 } else {
3853 if (len != 0) {
3854 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003855 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003856 goto drop;
3857 }
3858
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003859 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003860 }
3861
3862 return 0;
3863
3864drop:
3865 kfree_skb(skb);
3866 return 0;
3867}
3868
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
3870{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003871 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07003872 struct sock *sk = NULL;
Nathan Holstein51893f82010-06-09 15:46:25 -04003873 u16 control;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003874 u8 tx_seq;
3875 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003877 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003878 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 BT_DBG("unknown cid 0x%4.4x", cid);
3880 goto drop;
3881 }
3882
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003883 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003884
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003885 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003887 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 goto drop;
3889
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003890 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003891 case L2CAP_MODE_BASIC:
3892 /* If socket recv buffers overflows we drop data here
3893 * which is *bad* because L2CAP has to be reliable.
3894 * But we don't have any other choice. L2CAP doesn't
3895 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003897 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003898 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003900 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003901 goto done;
3902 break;
3903
3904 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003905 if (!sock_owned_by_user(sk)) {
3906 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003907 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003908 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003909 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003910 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003911
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02003912 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003913
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003914 case L2CAP_MODE_STREAMING:
3915 control = get_unaligned_le16(skb->data);
3916 skb_pull(skb, 2);
3917 len = skb->len;
3918
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003919 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03003920 goto drop;
3921
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003922 if (__is_sar_start(control))
3923 len -= 2;
3924
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003925 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003926 len -= 2;
3927
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003928 if (len > chan->mps || len < 0 || __is_sframe(control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003929 goto drop;
3930
3931 tx_seq = __get_txseq(control);
3932
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003933 if (chan->expected_tx_seq == tx_seq)
3934 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003935 else
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003936 chan->expected_tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003937
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003938 l2cap_streaming_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003939
3940 goto done;
3941
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003942 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003943 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003944 break;
3945 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003946
3947drop:
3948 kfree_skb(skb);
3949
3950done:
Marcel Holtmann01394182006-07-03 10:02:46 +02003951 if (sk)
3952 bh_unlock_sock(sk);
3953
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 return 0;
3955}
3956
Al Viro8e036fc2007-07-29 00:16:36 -07003957static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003959 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003960 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003962 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
3963 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 goto drop;
3965
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003966 sk = chan->sk;
3967
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00003968 bh_lock_sock(sk);
3969
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 BT_DBG("sk %p, len %d", sk, skb->len);
3971
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003972 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973 goto drop;
3974
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003975 if (l2cap_pi(sk)->chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 goto drop;
3977
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003978 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 goto done;
3980
3981drop:
3982 kfree_skb(skb);
3983
3984done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03003985 if (sk)
3986 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 return 0;
3988}
3989
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003990static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
3991{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003992 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003993 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003994
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003995 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
3996 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003997 goto drop;
3998
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003999 sk = chan->sk;
4000
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004001 bh_lock_sock(sk);
4002
4003 BT_DBG("sk %p, len %d", sk, skb->len);
4004
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004005 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004006 goto drop;
4007
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004008 if (l2cap_pi(sk)->chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004009 goto drop;
4010
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004011 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004012 goto done;
4013
4014drop:
4015 kfree_skb(skb);
4016
4017done:
4018 if (sk)
4019 bh_unlock_sock(sk);
4020 return 0;
4021}
4022
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4024{
4025 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004026 u16 cid, len;
4027 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028
4029 skb_pull(skb, L2CAP_HDR_SIZE);
4030 cid = __le16_to_cpu(lh->cid);
4031 len = __le16_to_cpu(lh->len);
4032
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004033 if (len != skb->len) {
4034 kfree_skb(skb);
4035 return;
4036 }
4037
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4039
4040 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004041 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004042 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004043 l2cap_sig_channel(conn, skb);
4044 break;
4045
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004046 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004047 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 skb_pull(skb, 2);
4049 l2cap_conless_channel(conn, psm, skb);
4050 break;
4051
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004052 case L2CAP_CID_LE_DATA:
4053 l2cap_att_channel(conn, cid, skb);
4054 break;
4055
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004056 case L2CAP_CID_SMP:
4057 if (smp_sig_channel(conn, skb))
4058 l2cap_conn_del(conn->hcon, EACCES);
4059 break;
4060
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 default:
4062 l2cap_data_channel(conn, cid, skb);
4063 break;
4064 }
4065}
4066
4067/* ---- L2CAP interface with lower layer (HCI) ---- */
4068
4069static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4070{
4071 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004072 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073
4074 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004075 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076
4077 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4078
4079 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004080 read_lock(&chan_list_lock);
4081 list_for_each_entry(c, &chan_list, global_l) {
4082 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004083
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004084 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 continue;
4086
4087 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004088 lm1 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004089 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004090 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004092 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4093 lm2 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004094 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004095 lm2 |= HCI_LM_MASTER;
4096 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004097 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004098 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099
4100 return exact ? lm1 : lm2;
4101}
4102
4103static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4104{
Marcel Holtmann01394182006-07-03 10:02:46 +02004105 struct l2cap_conn *conn;
4106
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4108
Ville Tervoacd7d372011-02-10 22:38:49 -03004109 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004110 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111
4112 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 conn = l2cap_conn_add(hcon, status);
4114 if (conn)
4115 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004116 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004117 l2cap_conn_del(hcon, bt_err(status));
4118
4119 return 0;
4120}
4121
Marcel Holtmann2950f212009-02-12 14:02:50 +01004122static int l2cap_disconn_ind(struct hci_conn *hcon)
4123{
4124 struct l2cap_conn *conn = hcon->l2cap_data;
4125
4126 BT_DBG("hcon %p", hcon);
4127
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004128 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004129 return 0x13;
4130
4131 return conn->disc_reason;
4132}
4133
4134static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135{
4136 BT_DBG("hcon %p reason %d", hcon, reason);
4137
Ville Tervoacd7d372011-02-10 22:38:49 -03004138 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004139 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140
4141 l2cap_conn_del(hcon, bt_err(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004142
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 return 0;
4144}
4145
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004146static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004147{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004148 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004149 return;
4150
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004151 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004152 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004153 __clear_chan_timer(chan);
4154 __set_chan_timer(chan, HZ * 5);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004155 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004156 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004157 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004158 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004159 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004160 }
4161}
4162
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004163static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004165 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004166 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167
Marcel Holtmann01394182006-07-03 10:02:46 +02004168 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004169 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004170
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171 BT_DBG("conn %p", conn);
4172
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004173 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004175 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004176 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004177
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 bh_lock_sock(sk);
4179
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004180 BT_DBG("chan->scid %d", chan->scid);
4181
4182 if (chan->scid == L2CAP_CID_LE_DATA) {
4183 if (!status && encrypt) {
4184 chan->sec_level = hcon->sec_level;
4185 l2cap_chan_ready(sk);
4186 }
4187
4188 bh_unlock_sock(sk);
4189 continue;
4190 }
4191
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004192 if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004193 bh_unlock_sock(sk);
4194 continue;
4195 }
4196
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004197 if (!status && (chan->state == BT_CONNECTED ||
4198 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004199 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004200 bh_unlock_sock(sk);
4201 continue;
4202 }
4203
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004204 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004205 if (!status) {
4206 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004207 req.scid = cpu_to_le16(chan->scid);
4208 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004209
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004210 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004211 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004212
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004213 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004214 L2CAP_CONN_REQ, sizeof(req), &req);
4215 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004216 __clear_chan_timer(chan);
4217 __set_chan_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004218 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004219 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004220 struct l2cap_conn_rsp rsp;
4221 __u16 result;
4222
4223 if (!status) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004224 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004225 result = L2CAP_CR_SUCCESS;
4226 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004227 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004228 __set_chan_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004229 result = L2CAP_CR_SEC_BLOCK;
4230 }
4231
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004232 rsp.scid = cpu_to_le16(chan->dcid);
4233 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004234 rsp.result = cpu_to_le16(result);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02004235 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004236 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4237 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 }
4239
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 bh_unlock_sock(sk);
4241 }
4242
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004243 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004244
Linus Torvalds1da177e2005-04-16 15:20:36 -07004245 return 0;
4246}
4247
4248static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4249{
4250 struct l2cap_conn *conn = hcon->l2cap_data;
4251
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004252 if (!conn)
4253 conn = l2cap_conn_add(hcon, 0);
4254
4255 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004256 goto drop;
4257
4258 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4259
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004260 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004262 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004263 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 int len;
4265
4266 if (conn->rx_len) {
4267 BT_ERR("Unexpected start frame (len %d)", skb->len);
4268 kfree_skb(conn->rx_skb);
4269 conn->rx_skb = NULL;
4270 conn->rx_len = 0;
4271 l2cap_conn_unreliable(conn, ECOMM);
4272 }
4273
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004274 /* Start fragment always begin with Basic L2CAP header */
4275 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 BT_ERR("Frame is too short (len %d)", skb->len);
4277 l2cap_conn_unreliable(conn, ECOMM);
4278 goto drop;
4279 }
4280
4281 hdr = (struct l2cap_hdr *) skb->data;
4282 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004283 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284
4285 if (len == skb->len) {
4286 /* Complete frame received */
4287 l2cap_recv_frame(conn, skb);
4288 return 0;
4289 }
4290
4291 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4292
4293 if (skb->len > len) {
4294 BT_ERR("Frame is too long (len %d, expected len %d)",
4295 skb->len, len);
4296 l2cap_conn_unreliable(conn, ECOMM);
4297 goto drop;
4298 }
4299
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004300 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004301
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004302 if (chan && chan->sk) {
4303 struct sock *sk = chan->sk;
4304
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004305 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004306 BT_ERR("Frame exceeding recv MTU (len %d, "
4307 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004308 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004309 bh_unlock_sock(sk);
4310 l2cap_conn_unreliable(conn, ECOMM);
4311 goto drop;
4312 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004313 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004314 }
4315
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004317 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4318 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319 goto drop;
4320
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004321 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004322 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 conn->rx_len = len - skb->len;
4324 } else {
4325 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4326
4327 if (!conn->rx_len) {
4328 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4329 l2cap_conn_unreliable(conn, ECOMM);
4330 goto drop;
4331 }
4332
4333 if (skb->len > conn->rx_len) {
4334 BT_ERR("Fragment is too long (len %d, expected %d)",
4335 skb->len, conn->rx_len);
4336 kfree_skb(conn->rx_skb);
4337 conn->rx_skb = NULL;
4338 conn->rx_len = 0;
4339 l2cap_conn_unreliable(conn, ECOMM);
4340 goto drop;
4341 }
4342
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004343 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004344 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345 conn->rx_len -= skb->len;
4346
4347 if (!conn->rx_len) {
4348 /* Complete frame received */
4349 l2cap_recv_frame(conn, conn->rx_skb);
4350 conn->rx_skb = NULL;
4351 }
4352 }
4353
4354drop:
4355 kfree_skb(skb);
4356 return 0;
4357}
4358
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004359static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004361 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004363 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004365 list_for_each_entry(c, &chan_list, global_l) {
4366 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004368 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 +01004369 batostr(&bt_sk(sk)->src),
4370 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004371 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004372 c->scid, c->dcid, c->imtu, c->omtu,
4373 c->sec_level, c->mode);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004374 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004376 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004377
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004378 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379}
4380
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004381static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4382{
4383 return single_open(file, l2cap_debugfs_show, inode->i_private);
4384}
4385
4386static const struct file_operations l2cap_debugfs_fops = {
4387 .open = l2cap_debugfs_open,
4388 .read = seq_read,
4389 .llseek = seq_lseek,
4390 .release = single_release,
4391};
4392
4393static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395static struct hci_proto l2cap_hci_proto = {
4396 .name = "L2CAP",
4397 .id = HCI_PROTO_L2CAP,
4398 .connect_ind = l2cap_connect_ind,
4399 .connect_cfm = l2cap_connect_cfm,
4400 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004401 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004402 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 .recv_acldata = l2cap_recv_acldata
4404};
4405
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004406int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407{
4408 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004409
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004410 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411 if (err < 0)
4412 return err;
4413
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004414 _busy_wq = create_singlethread_workqueue("l2cap");
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004415 if (!_busy_wq) {
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004416 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 goto error;
4418 }
4419
4420 err = hci_register_proto(&l2cap_hci_proto);
4421 if (err < 0) {
4422 BT_ERR("L2CAP protocol registration failed");
4423 bt_sock_unregister(BTPROTO_L2CAP);
4424 goto error;
4425 }
4426
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004427 if (bt_debugfs) {
4428 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4429 bt_debugfs, NULL, &l2cap_debugfs_fops);
4430 if (!l2cap_debugfs)
4431 BT_ERR("Failed to create L2CAP debug file");
4432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 return 0;
4435
4436error:
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004437 destroy_workqueue(_busy_wq);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004438 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004439 return err;
4440}
4441
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004442void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004444 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004446 flush_workqueue(_busy_wq);
4447 destroy_workqueue(_busy_wq);
4448
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4450 BT_ERR("L2CAP protocol unregistration failed");
4451
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004452 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453}
4454
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004455module_param(disable_ertm, bool, 0644);
4456MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");