blob: 8657165043967fbcff1fe24332c86005febec825 [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
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200893static void l2cap_conn_ready(struct l2cap_conn *conn)
894{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300895 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200896
897 BT_DBG("conn %p", conn);
898
Ville Tervob62f3282011-02-10 22:38:50 -0300899 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
900 l2cap_le_conn_ready(conn);
901
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300902 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200903
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300904 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300905 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300906
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200907 bh_lock_sock(sk);
908
Ville Tervoacd7d372011-02-10 22:38:49 -0300909 if (conn->hcon->type == LE_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300910 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300911 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervoacd7d372011-02-10 22:38:49 -0300912 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300913 if (smp_conn_security(conn, chan->sec_level))
914 BT_DBG("Insufficient security");
Ville Tervoacd7d372011-02-10 22:38:49 -0300915 }
916
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300917 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300918 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300919 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200920 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300921
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300922 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300923 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200924
925 bh_unlock_sock(sk);
926 }
927
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300928 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200929}
930
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200931/* Notify sockets that we cannot guaranty reliability anymore */
932static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
933{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300934 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200935
936 BT_DBG("conn %p", conn);
937
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300938 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200939
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300940 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300941 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300942
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300943 if (chan->force_reliable)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200944 sk->sk_err = err;
945 }
946
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300947 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200948}
949
950static void l2cap_info_timeout(unsigned long arg)
951{
952 struct l2cap_conn *conn = (void *) arg;
953
Marcel Holtmann984947d2009-02-06 23:35:19 +0100954 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100955 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100956
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200957 l2cap_conn_start(conn);
958}
959
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
961{
Marcel Holtmann01394182006-07-03 10:02:46 +0200962 struct l2cap_conn *conn = hcon->l2cap_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Marcel Holtmann01394182006-07-03 10:02:46 +0200964 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 return conn;
966
Marcel Holtmann01394182006-07-03 10:02:46 +0200967 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
968 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970
971 hcon->l2cap_data = conn;
972 conn->hcon = hcon;
973
Marcel Holtmann01394182006-07-03 10:02:46 +0200974 BT_DBG("hcon %p conn %p", hcon, conn);
975
Ville Tervoacd7d372011-02-10 22:38:49 -0300976 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
977 conn->mtu = hcon->hdev->le_mtu;
978 else
979 conn->mtu = hcon->hdev->acl_mtu;
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 conn->src = &hcon->hdev->bdaddr;
982 conn->dst = &hcon->dst;
983
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200984 conn->feat_mask = 0;
985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300987 rwlock_init(&conn->chan_lock);
988
989 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
Ville Tervob62f3282011-02-10 22:38:50 -0300991 if (hcon->type != LE_LINK)
992 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +0000993 (unsigned long) conn);
994
Marcel Holtmann2950f212009-02-12 14:02:50 +0100995 conn->disc_reason = 0x13;
996
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 return conn;
998}
999
Marcel Holtmann01394182006-07-03 10:02:46 +02001000static void l2cap_conn_del(struct hci_conn *hcon, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
Marcel Holtmann01394182006-07-03 10:02:46 +02001002 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001003 struct l2cap_chan *chan, *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 struct sock *sk;
1005
Marcel Holtmann01394182006-07-03 10:02:46 +02001006 if (!conn)
1007 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
1009 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1010
Wei Yongjun7585b972009-02-25 18:29:52 +08001011 kfree_skb(conn->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012
1013 /* Kill channels */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001014 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001015 sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 bh_lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001017 l2cap_chan_del(chan, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 bh_unlock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03001019 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 }
1021
Dave Young8e8440f2008-03-03 12:18:55 -08001022 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
1023 del_timer_sync(&conn->info_timer);
Thomas Gleixner3ab22732008-02-26 17:42:56 -08001024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 hcon->l2cap_data = NULL;
1026 kfree(conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027}
1028
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001029static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001031 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001032 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001033 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034}
1035
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038/* Find socket with psm and source bdaddr.
1039 * Returns closest match.
1040 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001041static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001043 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001045 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001046
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001047 list_for_each_entry(c, &chan_list, global_l) {
1048 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001049
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001050 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 continue;
1052
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001053 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001055 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001056 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001057 return c;
1058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
1060 /* Closest match */
1061 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001062 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 }
1064 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001066 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001067
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001068 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069}
1070
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001071int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001073 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 bdaddr_t *src = &bt_sk(sk)->src;
1075 bdaddr_t *dst = &bt_sk(sk)->dst;
1076 struct l2cap_conn *conn;
1077 struct hci_conn *hcon;
1078 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001079 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001080 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001082 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001083 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001085 hdev = hci_get_route(dst, src);
1086 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 return -EHOSTUNREACH;
1088
1089 hci_dev_lock_bh(hdev);
1090
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001091 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001092
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001093 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001094 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001095 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001096 else
1097 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001098 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001099
Ville Tervo30e76272011-02-22 16:10:53 -03001100 if (IS_ERR(hcon)) {
1101 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001103 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 conn = l2cap_conn_add(hcon, 0);
1106 if (!conn) {
1107 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001108 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 goto done;
1110 }
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 /* Update source addr of the socket */
1113 bacpy(src, conn->src);
1114
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001115 l2cap_chan_add(conn, chan);
1116
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001117 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001118 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119
1120 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001121 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001122 __clear_chan_timer(chan);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001123 if (l2cap_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001124 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001125 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001126 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 }
1128
Ville Tervo30e76272011-02-22 16:10:53 -03001129 err = 0;
1130
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131done:
1132 hci_dev_unlock_bh(hdev);
1133 hci_dev_put(hdev);
1134 return err;
1135}
1136
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001137int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001138{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001139 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001140 DECLARE_WAITQUEUE(wait, current);
1141 int err = 0;
1142 int timeo = HZ/5;
1143
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001144 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001145 while ((chan->unacked_frames > 0 && chan->conn)) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001146 set_current_state(TASK_INTERRUPTIBLE);
1147
1148 if (!timeo)
1149 timeo = HZ/5;
1150
1151 if (signal_pending(current)) {
1152 err = sock_intr_errno(timeo);
1153 break;
1154 }
1155
1156 release_sock(sk);
1157 timeo = schedule_timeout(timeo);
1158 lock_sock(sk);
1159
1160 err = sock_error(sk);
1161 if (err)
1162 break;
1163 }
1164 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001165 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001166 return err;
1167}
1168
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001169static void l2cap_monitor_timeout(unsigned long arg)
1170{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001171 struct l2cap_chan *chan = (void *) arg;
1172 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001173
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001174 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001175
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001176 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001177 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001178 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001179 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001180 return;
1181 }
1182
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001183 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001184 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001185
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001186 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001187 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001188}
1189
1190static void l2cap_retrans_timeout(unsigned long arg)
1191{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001192 struct l2cap_chan *chan = (void *) arg;
1193 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001194
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001195 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001196
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001197 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001198 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001199 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001200
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001201 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001202
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001203 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001204 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001205}
1206
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001207static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001208{
1209 struct sk_buff *skb;
1210
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001211 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001212 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001213 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001214 break;
1215
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001216 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001217 kfree_skb(skb);
1218
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001219 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001220 }
1221
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001222 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001223 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001224}
1225
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001226void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001227{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001228 struct hci_conn *hcon = chan->conn->hcon;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001229 u16 flags;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001230
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001231 BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001232
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001233 if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001234 flags = ACL_START_NO_FLUSH;
1235 else
1236 flags = ACL_START;
1237
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -07001238 bt_cb(skb)->force_active = chan->force_active;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001239 hci_send_acl(hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001240}
1241
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001242void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001243{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001244 struct sk_buff *skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001245 u16 control, fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001246
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001247 while ((skb = skb_dequeue(&chan->tx_q))) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001248 control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001249 control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001250 put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001251
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001252 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001253 fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
1254 put_unaligned_le16(fcs, skb->data + skb->len - 2);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001255 }
1256
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001257 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001258
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001259 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001260 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001261}
1262
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001263static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001264{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001265 struct sk_buff *skb, *tx_skb;
1266 u16 control, fcs;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001267
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001268 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001269 if (!skb)
1270 return;
1271
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001272 do {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001273 if (bt_cb(skb)->tx_seq == tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001274 break;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001275
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001276 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001277 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001278
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001279 } while ((skb = skb_queue_next(&chan->tx_q, skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001280
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001281 if (chan->remote_max_tx &&
1282 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001283 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001284 return;
1285 }
1286
1287 tx_skb = skb_clone(skb, GFP_ATOMIC);
1288 bt_cb(skb)->retries++;
1289 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Ruiyi Zhanga429b512011-04-18 11:04:30 +08001290 control &= L2CAP_CTRL_SAR;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001291
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001292 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001293 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001294 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001295 }
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001296
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001297 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001298 | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001299
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001300 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1301
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001302 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001303 fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
1304 put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
1305 }
1306
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001307 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001308}
1309
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001310int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001311{
1312 struct sk_buff *skb, *tx_skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001313 u16 control, fcs;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001314 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001315
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001316 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001317 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001318
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001319 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001320
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001321 if (chan->remote_max_tx &&
1322 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001323 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001324 break;
1325 }
1326
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001327 tx_skb = skb_clone(skb, GFP_ATOMIC);
1328
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001329 bt_cb(skb)->retries++;
1330
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001331 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001332 control &= L2CAP_CTRL_SAR;
1333
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001334 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001335 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001336 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001337 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001338 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
1339 | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001340 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1341
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001342
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001343 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001344 fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
1345 put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
1346 }
1347
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001348 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001349
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001350 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001351
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001352 bt_cb(skb)->tx_seq = chan->next_tx_seq;
1353 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001354
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301355 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001356 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301357
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001358 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001359
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001360 if (skb_queue_is_last(&chan->tx_q, skb))
1361 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001362 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001363 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001364
1365 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001366 }
1367
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001368 return nsent;
1369}
1370
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001371static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001372{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001373 int ret;
1374
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001375 if (!skb_queue_empty(&chan->tx_q))
1376 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001377
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001378 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001379 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001380 return ret;
1381}
1382
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001383static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001384{
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001385 u16 control = 0;
1386
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001387 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001388
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001389 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001390 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001391 chan->conn_state |= L2CAP_CONN_RNR_SENT;
1392 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001393 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001394 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001395
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001396 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001397 return;
1398
1399 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001400 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001401}
1402
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001403static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001404{
1405 struct srej_list *tail;
1406 u16 control;
1407
1408 control = L2CAP_SUPER_SELECT_REJECT;
1409 control |= L2CAP_CTRL_FINAL;
1410
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001411 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001412 control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
1413
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001414 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001415}
1416
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001417static 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 -07001418{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001419 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001420 struct sk_buff **frag;
1421 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001423 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001424 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426 sent += count;
1427 len -= count;
1428
1429 /* Continuation fragments (no L2CAP header) */
1430 frag = &skb_shinfo(skb)->frag_list;
1431 while (len) {
1432 count = min_t(unsigned int, conn->mtu, len);
1433
1434 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1435 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001436 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001437 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1438 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
1440 sent += count;
1441 len -= count;
1442
1443 frag = &(*frag)->next;
1444 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445
1446 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001447}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001449struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001450{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001451 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001452 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001453 struct sk_buff *skb;
1454 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1455 struct l2cap_hdr *lh;
1456
1457 BT_DBG("sk %p len %d", sk, (int)len);
1458
1459 count = min_t(unsigned int, (conn->mtu - hlen), len);
1460 skb = bt_skb_send_alloc(sk, count + hlen,
1461 msg->msg_flags & MSG_DONTWAIT, &err);
1462 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001463 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001464
1465 /* Create L2CAP header */
1466 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001467 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001468 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001469 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001470
1471 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1472 if (unlikely(err < 0)) {
1473 kfree_skb(skb);
1474 return ERR_PTR(err);
1475 }
1476 return skb;
1477}
1478
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001479struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001480{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001481 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001482 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001483 struct sk_buff *skb;
1484 int err, count, hlen = L2CAP_HDR_SIZE;
1485 struct l2cap_hdr *lh;
1486
1487 BT_DBG("sk %p len %d", sk, (int)len);
1488
1489 count = min_t(unsigned int, (conn->mtu - hlen), len);
1490 skb = bt_skb_send_alloc(sk, count + hlen,
1491 msg->msg_flags & MSG_DONTWAIT, &err);
1492 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001493 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001494
1495 /* Create L2CAP header */
1496 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001497 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001498 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1499
1500 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1501 if (unlikely(err < 0)) {
1502 kfree_skb(skb);
1503 return ERR_PTR(err);
1504 }
1505 return skb;
1506}
1507
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001508struct 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 -03001509{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001510 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001511 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001512 struct sk_buff *skb;
1513 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1514 struct l2cap_hdr *lh;
1515
1516 BT_DBG("sk %p len %d", sk, (int)len);
1517
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001518 if (!conn)
1519 return ERR_PTR(-ENOTCONN);
1520
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001521 if (sdulen)
1522 hlen += 2;
1523
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001524 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001525 hlen += 2;
1526
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001527 count = min_t(unsigned int, (conn->mtu - hlen), len);
1528 skb = bt_skb_send_alloc(sk, count + hlen,
1529 msg->msg_flags & MSG_DONTWAIT, &err);
1530 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001531 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001532
1533 /* Create L2CAP header */
1534 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001535 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001536 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1537 put_unaligned_le16(control, skb_put(skb, 2));
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001538 if (sdulen)
1539 put_unaligned_le16(sdulen, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001540
1541 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1542 if (unlikely(err < 0)) {
1543 kfree_skb(skb);
1544 return ERR_PTR(err);
1545 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001546
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001547 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001548 put_unaligned_le16(0, skb_put(skb, 2));
1549
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001550 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001551 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552}
1553
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001554int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001555{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001556 struct sk_buff *skb;
1557 struct sk_buff_head sar_queue;
1558 u16 control;
1559 size_t size = 0;
1560
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001561 skb_queue_head_init(&sar_queue);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001562 control = L2CAP_SDU_START;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001563 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001564 if (IS_ERR(skb))
1565 return PTR_ERR(skb);
1566
1567 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001568 len -= chan->remote_mps;
1569 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001570
1571 while (len > 0) {
1572 size_t buflen;
1573
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001574 if (len > chan->remote_mps) {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001575 control = L2CAP_SDU_CONTINUE;
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001576 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001577 } else {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001578 control = L2CAP_SDU_END;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001579 buflen = len;
1580 }
1581
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001582 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001583 if (IS_ERR(skb)) {
1584 skb_queue_purge(&sar_queue);
1585 return PTR_ERR(skb);
1586 }
1587
1588 __skb_queue_tail(&sar_queue, skb);
1589 len -= buflen;
1590 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001591 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001592 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1593 if (chan->tx_send_head == NULL)
1594 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001595
1596 return size;
1597}
1598
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001599int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
1600{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001601 struct sk_buff *skb;
1602 u16 control;
1603 int err;
1604
1605 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001606 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001607 skb = l2cap_create_connless_pdu(chan, msg, len);
1608 if (IS_ERR(skb))
1609 return PTR_ERR(skb);
1610
1611 l2cap_do_send(chan, skb);
1612 return len;
1613 }
1614
1615 switch (chan->mode) {
1616 case L2CAP_MODE_BASIC:
1617 /* Check outgoing MTU */
1618 if (len > chan->omtu)
1619 return -EMSGSIZE;
1620
1621 /* Create a basic PDU */
1622 skb = l2cap_create_basic_pdu(chan, msg, len);
1623 if (IS_ERR(skb))
1624 return PTR_ERR(skb);
1625
1626 l2cap_do_send(chan, skb);
1627 err = len;
1628 break;
1629
1630 case L2CAP_MODE_ERTM:
1631 case L2CAP_MODE_STREAMING:
1632 /* Entire SDU fits into one PDU */
1633 if (len <= chan->remote_mps) {
1634 control = L2CAP_SDU_UNSEGMENTED;
1635 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1636 0);
1637 if (IS_ERR(skb))
1638 return PTR_ERR(skb);
1639
1640 __skb_queue_tail(&chan->tx_q, skb);
1641
1642 if (chan->tx_send_head == NULL)
1643 chan->tx_send_head = skb;
1644
1645 } else {
1646 /* Segment SDU into multiples PDUs */
1647 err = l2cap_sar_segment_sdu(chan, msg, len);
1648 if (err < 0)
1649 return err;
1650 }
1651
1652 if (chan->mode == L2CAP_MODE_STREAMING) {
1653 l2cap_streaming_send(chan);
1654 err = len;
1655 break;
1656 }
1657
1658 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
1659 (chan->conn_state & L2CAP_CONN_WAIT_F)) {
1660 err = len;
1661 break;
1662 }
1663
1664 err = l2cap_ertm_send(chan);
1665 if (err >= 0)
1666 err = len;
1667
1668 break;
1669
1670 default:
1671 BT_DBG("bad state %1.1x", chan->mode);
1672 err = -EBADFD;
1673 }
1674
1675 return err;
1676}
1677
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678static void l2cap_chan_ready(struct sock *sk)
1679{
1680 struct sock *parent = bt_sk(sk)->parent;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001681 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682
1683 BT_DBG("sk %p, parent %p", sk, parent);
1684
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001685 chan->conf_state = 0;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001686 __clear_chan_timer(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688 if (!parent) {
1689 /* Outgoing channel.
1690 * Wake up socket sleeping on connect.
1691 */
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001692 l2cap_state_change(chan, BT_CONNECTED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 sk->sk_state_change(sk);
1694 } else {
1695 /* Incoming channel.
1696 * Wake up socket sleeping on accept.
1697 */
1698 parent->sk_data_ready(parent, 0);
1699 }
1700}
1701
1702/* Copy frame to all raw sockets on that connection */
1703static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1704{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001706 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707
1708 BT_DBG("conn %p", conn);
1709
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001710 read_lock(&conn->chan_lock);
1711 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001712 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001713 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 continue;
1715
1716 /* Don't send frame to the socket it came from */
1717 if (skb->sk == sk)
1718 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001719 nskb = skb_clone(skb, GFP_ATOMIC);
1720 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721 continue;
1722
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001723 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 kfree_skb(nskb);
1725 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001726 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001727}
1728
1729/* ---- L2CAP signalling commands ---- */
1730static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1731 u8 code, u8 ident, u16 dlen, void *data)
1732{
1733 struct sk_buff *skb, **frag;
1734 struct l2cap_cmd_hdr *cmd;
1735 struct l2cap_hdr *lh;
1736 int len, count;
1737
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001738 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1739 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
1741 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1742 count = min_t(unsigned int, conn->mtu, len);
1743
1744 skb = bt_skb_alloc(count, GFP_ATOMIC);
1745 if (!skb)
1746 return NULL;
1747
1748 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001749 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001750
1751 if (conn->hcon->type == LE_LINK)
1752 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1753 else
1754 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
1756 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1757 cmd->code = code;
1758 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001759 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760
1761 if (dlen) {
1762 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1763 memcpy(skb_put(skb, count), data, count);
1764 data += count;
1765 }
1766
1767 len -= skb->len;
1768
1769 /* Continuation fragments (no L2CAP header) */
1770 frag = &skb_shinfo(skb)->frag_list;
1771 while (len) {
1772 count = min_t(unsigned int, conn->mtu, len);
1773
1774 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1775 if (!*frag)
1776 goto fail;
1777
1778 memcpy(skb_put(*frag, count), data, count);
1779
1780 len -= count;
1781 data += count;
1782
1783 frag = &(*frag)->next;
1784 }
1785
1786 return skb;
1787
1788fail:
1789 kfree_skb(skb);
1790 return NULL;
1791}
1792
1793static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1794{
1795 struct l2cap_conf_opt *opt = *ptr;
1796 int len;
1797
1798 len = L2CAP_CONF_OPT_SIZE + opt->len;
1799 *ptr += len;
1800
1801 *type = opt->type;
1802 *olen = opt->len;
1803
1804 switch (opt->len) {
1805 case 1:
1806 *val = *((u8 *) opt->val);
1807 break;
1808
1809 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001810 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 break;
1812
1813 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001814 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 break;
1816
1817 default:
1818 *val = (unsigned long) opt->val;
1819 break;
1820 }
1821
1822 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1823 return len;
1824}
1825
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1827{
1828 struct l2cap_conf_opt *opt = *ptr;
1829
1830 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1831
1832 opt->type = type;
1833 opt->len = len;
1834
1835 switch (len) {
1836 case 1:
1837 *((u8 *) opt->val) = val;
1838 break;
1839
1840 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001841 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 break;
1843
1844 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001845 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 break;
1847
1848 default:
1849 memcpy(opt->val, (void *) val, len);
1850 break;
1851 }
1852
1853 *ptr += L2CAP_CONF_OPT_SIZE + len;
1854}
1855
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001856static void l2cap_ack_timeout(unsigned long arg)
1857{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001858 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001859
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001860 bh_lock_sock(chan->sk);
1861 l2cap_send_ack(chan);
1862 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001863}
1864
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001865static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001866{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001867 struct sock *sk = chan->sk;
1868
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001869 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001870 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001871 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001872 chan->num_acked = 0;
1873 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001874
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001875 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1876 (unsigned long) chan);
1877 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1878 (unsigned long) chan);
1879 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001880
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001881 skb_queue_head_init(&chan->srej_q);
1882 skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001883
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001884 INIT_LIST_HEAD(&chan->srej_l);
1885
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03001886 INIT_WORK(&chan->busy_work, l2cap_busy_work);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001887
1888 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001889}
1890
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001891static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1892{
1893 switch (mode) {
1894 case L2CAP_MODE_STREAMING:
1895 case L2CAP_MODE_ERTM:
1896 if (l2cap_mode_supported(mode, remote_feat_mask))
1897 return mode;
1898 /* fall through */
1899 default:
1900 return L2CAP_MODE_BASIC;
1901 }
1902}
1903
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03001904static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001907 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 void *ptr = req->data;
1909
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001910 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001912 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001913 goto done;
1914
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001915 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001916 case L2CAP_MODE_STREAMING:
1917 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001918 if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001919 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001920
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03001921 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001922 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001923 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001924 break;
1925 }
1926
1927done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001928 if (chan->imtu != L2CAP_DEFAULT_MTU)
1929 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02001930
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001931 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001932 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001933 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
1934 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001935 break;
1936
Gustavo F. Padovan62547752010-06-08 20:05:31 -03001937 rfc.mode = L2CAP_MODE_BASIC;
1938 rfc.txwin_size = 0;
1939 rfc.max_transmit = 0;
1940 rfc.retrans_timeout = 0;
1941 rfc.monitor_timeout = 0;
1942 rfc.max_pdu_size = 0;
1943
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001944 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1945 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001946 break;
1947
1948 case L2CAP_MODE_ERTM:
1949 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001950 rfc.txwin_size = chan->tx_win;
1951 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001952 rfc.retrans_timeout = 0;
1953 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001954 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001955 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1956 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001957
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001958 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1959 (unsigned long) &rfc);
1960
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001961 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001962 break;
1963
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001964 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001965 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001966 chan->fcs = L2CAP_FCS_NONE;
1967 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001968 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001969 break;
1970
1971 case L2CAP_MODE_STREAMING:
1972 rfc.mode = L2CAP_MODE_STREAMING;
1973 rfc.txwin_size = 0;
1974 rfc.max_transmit = 0;
1975 rfc.retrans_timeout = 0;
1976 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001977 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001978 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1979 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001980
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001981 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1982 (unsigned long) &rfc);
1983
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001984 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001985 break;
1986
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001987 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001988 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001989 chan->fcs = L2CAP_FCS_NONE;
1990 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001991 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001992 break;
1993 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001995 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001996 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
1998 return ptr - data;
1999}
2000
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002001static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002003 struct l2cap_conf_rsp *rsp = data;
2004 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002005 void *req = chan->conf_req;
2006 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002007 int type, hint, olen;
2008 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002009 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Marcel Holtmann861d6882007-10-20 13:37:06 +02002010 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002011 u16 result = L2CAP_CONF_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002013 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002014
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002015 while (len >= L2CAP_CONF_OPT_SIZE) {
2016 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002018 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002019 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002020
2021 switch (type) {
2022 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002023 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002024 break;
2025
2026 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002027 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002028 break;
2029
2030 case L2CAP_CONF_QOS:
2031 break;
2032
Marcel Holtmann6464f352007-10-20 13:39:51 +02002033 case L2CAP_CONF_RFC:
2034 if (olen == sizeof(rfc))
2035 memcpy(&rfc, (void *) val, olen);
2036 break;
2037
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002038 case L2CAP_CONF_FCS:
2039 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002040 chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002041
2042 break;
2043
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002044 default:
2045 if (hint)
2046 break;
2047
2048 result = L2CAP_CONF_UNKNOWN;
2049 *((u8 *) ptr++) = type;
2050 break;
2051 }
2052 }
2053
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002054 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002055 goto done;
2056
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002057 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002058 case L2CAP_MODE_STREAMING:
2059 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002060 if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002061 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002062 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002063 break;
2064 }
2065
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002066 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002067 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002068
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002069 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002070 }
2071
2072done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002073 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002074 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002075 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002076
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002077 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002078 return -ECONNREFUSED;
2079
2080 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2081 sizeof(rfc), (unsigned long) &rfc);
2082 }
2083
2084
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002085 if (result == L2CAP_CONF_SUCCESS) {
2086 /* Configure output options and let the other side know
2087 * which ones we don't like. */
2088
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002089 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2090 result = L2CAP_CONF_UNACCEPT;
2091 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002092 chan->omtu = mtu;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002093 chan->conf_state |= L2CAP_CONF_MTU_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002094 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002095 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002096
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002097 switch (rfc.mode) {
2098 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002099 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002100 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002101 break;
2102
2103 case L2CAP_MODE_ERTM:
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002104 chan->remote_tx_win = rfc.txwin_size;
2105 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002106
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002107 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2108 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002109
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002110 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002111
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002112 rfc.retrans_timeout =
2113 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2114 rfc.monitor_timeout =
2115 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002116
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002117 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002118
2119 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2120 sizeof(rfc), (unsigned long) &rfc);
2121
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002122 break;
2123
2124 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002125 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2126 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002127
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002128 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002129
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002130 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002131
2132 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2133 sizeof(rfc), (unsigned long) &rfc);
2134
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002135 break;
2136
2137 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002138 result = L2CAP_CONF_UNACCEPT;
2139
2140 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002141 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002142 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002143
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002144 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002145 chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002146 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002147 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002148 rsp->result = cpu_to_le16(result);
2149 rsp->flags = cpu_to_le16(0x0000);
2150
2151 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152}
2153
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002154static 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 -03002155{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002156 struct l2cap_conf_req *req = data;
2157 void *ptr = req->data;
2158 int type, olen;
2159 unsigned long val;
2160 struct l2cap_conf_rfc rfc;
2161
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002162 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002163
2164 while (len >= L2CAP_CONF_OPT_SIZE) {
2165 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2166
2167 switch (type) {
2168 case L2CAP_CONF_MTU:
2169 if (val < L2CAP_DEFAULT_MIN_MTU) {
2170 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002171 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002172 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002173 chan->imtu = val;
2174 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002175 break;
2176
2177 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002178 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002179 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002180 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002181 break;
2182
2183 case L2CAP_CONF_RFC:
2184 if (olen == sizeof(rfc))
2185 memcpy(&rfc, (void *)val, olen);
2186
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002187 if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002188 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002189 return -ECONNREFUSED;
2190
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002191 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002192
2193 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2194 sizeof(rfc), (unsigned long) &rfc);
2195 break;
2196 }
2197 }
2198
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002199 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002200 return -ECONNREFUSED;
2201
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002202 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002203
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002204 if (*result == L2CAP_CONF_SUCCESS) {
2205 switch (rfc.mode) {
2206 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002207 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2208 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2209 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002210 break;
2211 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002212 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002213 }
2214 }
2215
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002216 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002217 req->flags = cpu_to_le16(0x0000);
2218
2219 return ptr - data;
2220}
2221
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002222static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223{
2224 struct l2cap_conf_rsp *rsp = data;
2225 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002227 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002229 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002230 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002231 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002232
2233 return ptr - data;
2234}
2235
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002236void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002237{
2238 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002239 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002240 u8 buf[128];
2241
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002242 rsp.scid = cpu_to_le16(chan->dcid);
2243 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002244 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2245 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2246 l2cap_send_cmd(conn, chan->ident,
2247 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2248
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002249 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002250 return;
2251
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002252 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002253 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2254 l2cap_build_conf_req(chan, buf), buf);
2255 chan->num_conf_req++;
2256}
2257
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002258static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002259{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002260 int type, olen;
2261 unsigned long val;
2262 struct l2cap_conf_rfc rfc;
2263
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002264 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002265
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002266 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002267 return;
2268
2269 while (len >= L2CAP_CONF_OPT_SIZE) {
2270 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2271
2272 switch (type) {
2273 case L2CAP_CONF_RFC:
2274 if (olen == sizeof(rfc))
2275 memcpy(&rfc, (void *)val, olen);
2276 goto done;
2277 }
2278 }
2279
2280done:
2281 switch (rfc.mode) {
2282 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002283 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2284 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2285 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002286 break;
2287 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002288 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002289 }
2290}
2291
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002292static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2293{
2294 struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
2295
2296 if (rej->reason != 0x0000)
2297 return 0;
2298
2299 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2300 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002301 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002302
2303 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002304 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002305
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002306 l2cap_conn_start(conn);
2307 }
2308
2309 return 0;
2310}
2311
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2313{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2315 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002316 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002317 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002318 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
2320 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002321 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322
2323 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2324
2325 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002326 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2327 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 result = L2CAP_CR_BAD_PSM;
2329 goto sendresp;
2330 }
2331
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002332 parent = pchan->sk;
2333
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002334 bh_lock_sock(parent);
2335
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002336 /* Check if the ACL is secure enough (if not SDP) */
2337 if (psm != cpu_to_le16(0x0001) &&
2338 !hci_conn_check_link_mode(conn->hcon)) {
Marcel Holtmann2950f212009-02-12 14:02:50 +01002339 conn->disc_reason = 0x05;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002340 result = L2CAP_CR_SEC_BLOCK;
2341 goto response;
2342 }
2343
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 result = L2CAP_CR_NO_MEM;
2345
2346 /* Check for backlog size */
2347 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002348 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 goto response;
2350 }
2351
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002352 chan = pchan->ops->new_connection(pchan->data);
2353 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 goto response;
2355
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002356 sk = chan->sk;
2357
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002358 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359
2360 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002361 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2362 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002364 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 goto response;
2366 }
2367
2368 hci_conn_hold(conn->hcon);
2369
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370 bacpy(&bt_sk(sk)->src, conn->src);
2371 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002372 chan->psm = psm;
2373 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002375 bt_accept_enqueue(parent, sk);
2376
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002377 __l2cap_chan_add(conn, chan);
2378
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002379 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002381 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002383 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384
Marcel Holtmann984947d2009-02-06 23:35:19 +01002385 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03002386 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002387 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002388 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002389 result = L2CAP_CR_PEND;
2390 status = L2CAP_CS_AUTHOR_PEND;
2391 parent->sk_data_ready(parent, 0);
2392 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002393 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002394 result = L2CAP_CR_SUCCESS;
2395 status = L2CAP_CS_NO_INFO;
2396 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002397 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002398 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002399 result = L2CAP_CR_PEND;
2400 status = L2CAP_CS_AUTHEN_PEND;
2401 }
2402 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002403 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002404 result = L2CAP_CR_PEND;
2405 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 }
2407
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002408 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409
2410response:
2411 bh_unlock_sock(parent);
2412
2413sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002414 rsp.scid = cpu_to_le16(scid);
2415 rsp.dcid = cpu_to_le16(dcid);
2416 rsp.result = cpu_to_le16(result);
2417 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002419
2420 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2421 struct l2cap_info_req info;
2422 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2423
2424 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2425 conn->info_ident = l2cap_get_ident(conn);
2426
2427 mod_timer(&conn->info_timer, jiffies +
2428 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2429
2430 l2cap_send_cmd(conn, conn->info_ident,
2431 L2CAP_INFO_REQ, sizeof(info), &info);
2432 }
2433
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002434 if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002435 result == L2CAP_CR_SUCCESS) {
2436 u8 buf[128];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002437 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002438 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002439 l2cap_build_conf_req(chan, buf), buf);
2440 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002441 }
2442
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 return 0;
2444}
2445
2446static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2447{
2448 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2449 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002450 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 struct sock *sk;
2452 u8 req[128];
2453
2454 scid = __le16_to_cpu(rsp->scid);
2455 dcid = __le16_to_cpu(rsp->dcid);
2456 result = __le16_to_cpu(rsp->result);
2457 status = __le16_to_cpu(rsp->status);
2458
2459 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2460
2461 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002462 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002463 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002464 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002466 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002467 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002468 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 }
2470
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002471 sk = chan->sk;
2472
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 switch (result) {
2474 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002475 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002476 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002477 chan->dcid = dcid;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002478 chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002479
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002480 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002481 break;
2482
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002483 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002484
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002486 l2cap_build_conf_req(chan, req), req);
2487 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 break;
2489
2490 case L2CAP_CR_PEND:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002491 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492 break;
2493
2494 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002495 /* don't delete l2cap channel if sk is owned by user */
2496 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002497 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002498 __clear_chan_timer(chan);
2499 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002500 break;
2501 }
2502
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002503 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 break;
2505 }
2506
2507 bh_unlock_sock(sk);
2508 return 0;
2509}
2510
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002511static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002512{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002513 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
2514
Mat Martineau8c462b62010-08-24 15:35:42 -07002515 /* FCS is enabled only in ERTM or streaming mode, if one or both
2516 * sides request it.
2517 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002518 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002519 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002520 else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002521 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002522}
2523
Al Viro88219a02007-07-29 00:17:25 -07002524static 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 -07002525{
2526 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2527 u16 dcid, flags;
2528 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002529 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002531 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532
2533 dcid = __le16_to_cpu(req->dcid);
2534 flags = __le16_to_cpu(req->flags);
2535
2536 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2537
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002538 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002539 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 return -ENOENT;
2541
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002542 sk = chan->sk;
2543
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002544 if (chan->state != BT_CONFIG) {
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002545 struct l2cap_cmd_rej rej;
2546
2547 rej.reason = cpu_to_le16(0x0002);
2548 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2549 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002550 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002551 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002552
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002553 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002554 len = cmd_len - sizeof(*req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002555 if (chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002556 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002557 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002558 L2CAP_CONF_REJECT, flags), rsp);
2559 goto unlock;
2560 }
2561
2562 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002563 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2564 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565
2566 if (flags & 0x0001) {
2567 /* Incomplete config. Send empty response. */
2568 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002569 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002570 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 goto unlock;
2572 }
2573
2574 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002575 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002576 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002577 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002579 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002581 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002582 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002583
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002584 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002585 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002586
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002587 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002588 goto unlock;
2589
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002590 if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002591 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002592
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002593 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002594
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002595 chan->next_tx_seq = 0;
2596 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002597 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002598 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002599 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002600
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002602 goto unlock;
2603 }
2604
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002605 if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002606 u8 buf[64];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002607 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002609 l2cap_build_conf_req(chan, buf), buf);
2610 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 }
2612
2613unlock:
2614 bh_unlock_sock(sk);
2615 return 0;
2616}
2617
2618static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2619{
2620 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2621 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002622 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002624 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
2626 scid = __le16_to_cpu(rsp->scid);
2627 flags = __le16_to_cpu(rsp->flags);
2628 result = __le16_to_cpu(rsp->result);
2629
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002630 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2631 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002633 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002634 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 return 0;
2636
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002637 sk = chan->sk;
2638
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 switch (result) {
2640 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002641 l2cap_conf_rfc_get(chan, rsp->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 break;
2643
2644 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002645 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002646 char req[64];
2647
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002648 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002649 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002650 goto done;
2651 }
2652
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002653 /* throw out any old stored conf requests */
2654 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002655 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2656 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002657 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002658 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002659 goto done;
2660 }
2661
2662 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2663 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002664 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002665 if (result != L2CAP_CONF_SUCCESS)
2666 goto done;
2667 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 }
2669
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002670 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002671 sk->sk_err = ECONNRESET;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002672 __set_chan_timer(chan, HZ * 5);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002673 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 goto done;
2675 }
2676
2677 if (flags & 0x01)
2678 goto done;
2679
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002680 chan->conf_state |= L2CAP_CONF_INPUT_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002682 if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002683 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002684
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002685 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002686 chan->next_tx_seq = 0;
2687 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002688 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002689 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002690 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002691
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 l2cap_chan_ready(sk);
2693 }
2694
2695done:
2696 bh_unlock_sock(sk);
2697 return 0;
2698}
2699
2700static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2701{
2702 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2703 struct l2cap_disconn_rsp rsp;
2704 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002705 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 struct sock *sk;
2707
2708 scid = __le16_to_cpu(req->scid);
2709 dcid = __le16_to_cpu(req->dcid);
2710
2711 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2712
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002713 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002714 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 return 0;
2716
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002717 sk = chan->sk;
2718
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002719 rsp.dcid = cpu_to_le16(chan->scid);
2720 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2722
2723 sk->sk_shutdown = SHUTDOWN_MASK;
2724
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002725 /* don't delete l2cap channel if sk is owned by user */
2726 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002727 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002728 __clear_chan_timer(chan);
2729 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002730 bh_unlock_sock(sk);
2731 return 0;
2732 }
2733
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002734 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 bh_unlock_sock(sk);
2736
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002737 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 return 0;
2739}
2740
2741static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2742{
2743 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
2744 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002745 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 struct sock *sk;
2747
2748 scid = __le16_to_cpu(rsp->scid);
2749 dcid = __le16_to_cpu(rsp->dcid);
2750
2751 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
2752
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002753 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002754 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 return 0;
2756
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002757 sk = chan->sk;
2758
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002759 /* don't delete l2cap channel if sk is owned by user */
2760 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002761 l2cap_state_change(chan,BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002762 __clear_chan_timer(chan);
2763 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002764 bh_unlock_sock(sk);
2765 return 0;
2766 }
2767
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002768 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 bh_unlock_sock(sk);
2770
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002771 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 return 0;
2773}
2774
2775static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2776{
2777 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 u16 type;
2779
2780 type = __le16_to_cpu(req->type);
2781
2782 BT_DBG("type 0x%4.4x", type);
2783
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002784 if (type == L2CAP_IT_FEAT_MASK) {
2785 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07002786 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002787 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2788 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2789 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03002790 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002791 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
2792 | L2CAP_FEAT_FCS;
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03002793 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002794 l2cap_send_cmd(conn, cmd->ident,
2795 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002796 } else if (type == L2CAP_IT_FIXED_CHAN) {
2797 u8 buf[12];
2798 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2799 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2800 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
2801 memcpy(buf + 4, l2cap_fixed_chan, 8);
2802 l2cap_send_cmd(conn, cmd->ident,
2803 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002804 } else {
2805 struct l2cap_info_rsp rsp;
2806 rsp.type = cpu_to_le16(type);
2807 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
2808 l2cap_send_cmd(conn, cmd->ident,
2809 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
2810 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811
2812 return 0;
2813}
2814
2815static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2816{
2817 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
2818 u16 type, result;
2819
2820 type = __le16_to_cpu(rsp->type);
2821 result = __le16_to_cpu(rsp->result);
2822
2823 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
2824
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02002825 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
2826 if (cmd->ident != conn->info_ident ||
2827 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
2828 return 0;
2829
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002830 del_timer(&conn->info_timer);
2831
Ville Tervoadb08ed2010-08-04 09:43:33 +03002832 if (result != L2CAP_IR_SUCCESS) {
2833 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2834 conn->info_ident = 0;
2835
2836 l2cap_conn_start(conn);
2837
2838 return 0;
2839 }
2840
Marcel Holtmann984947d2009-02-06 23:35:19 +01002841 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07002842 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002843
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002844 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002845 struct l2cap_info_req req;
2846 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2847
2848 conn->info_ident = l2cap_get_ident(conn);
2849
2850 l2cap_send_cmd(conn, conn->info_ident,
2851 L2CAP_INFO_REQ, sizeof(req), &req);
2852 } else {
2853 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2854 conn->info_ident = 0;
2855
2856 l2cap_conn_start(conn);
2857 }
2858 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01002859 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002860 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002861
2862 l2cap_conn_start(conn);
2863 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002864
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 return 0;
2866}
2867
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002868static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02002869 u16 to_multiplier)
2870{
2871 u16 max_latency;
2872
2873 if (min > max || min < 6 || max > 3200)
2874 return -EINVAL;
2875
2876 if (to_multiplier < 10 || to_multiplier > 3200)
2877 return -EINVAL;
2878
2879 if (max >= to_multiplier * 8)
2880 return -EINVAL;
2881
2882 max_latency = (to_multiplier * 8 / max) - 1;
2883 if (latency > 499 || latency > max_latency)
2884 return -EINVAL;
2885
2886 return 0;
2887}
2888
2889static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
2890 struct l2cap_cmd_hdr *cmd, u8 *data)
2891{
2892 struct hci_conn *hcon = conn->hcon;
2893 struct l2cap_conn_param_update_req *req;
2894 struct l2cap_conn_param_update_rsp rsp;
2895 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002896 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02002897
2898 if (!(hcon->link_mode & HCI_LM_MASTER))
2899 return -EINVAL;
2900
2901 cmd_len = __le16_to_cpu(cmd->len);
2902 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
2903 return -EPROTO;
2904
2905 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002906 min = __le16_to_cpu(req->min);
2907 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02002908 latency = __le16_to_cpu(req->latency);
2909 to_multiplier = __le16_to_cpu(req->to_multiplier);
2910
2911 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
2912 min, max, latency, to_multiplier);
2913
2914 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002915
2916 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
2917 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02002918 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
2919 else
2920 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
2921
2922 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
2923 sizeof(rsp), &rsp);
2924
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002925 if (!err)
2926 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
2927
Claudio Takahaside731152011-02-11 19:28:55 -02002928 return 0;
2929}
2930
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002931static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
2932 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
2933{
2934 int err = 0;
2935
2936 switch (cmd->code) {
2937 case L2CAP_COMMAND_REJ:
2938 l2cap_command_rej(conn, cmd, data);
2939 break;
2940
2941 case L2CAP_CONN_REQ:
2942 err = l2cap_connect_req(conn, cmd, data);
2943 break;
2944
2945 case L2CAP_CONN_RSP:
2946 err = l2cap_connect_rsp(conn, cmd, data);
2947 break;
2948
2949 case L2CAP_CONF_REQ:
2950 err = l2cap_config_req(conn, cmd, cmd_len, data);
2951 break;
2952
2953 case L2CAP_CONF_RSP:
2954 err = l2cap_config_rsp(conn, cmd, data);
2955 break;
2956
2957 case L2CAP_DISCONN_REQ:
2958 err = l2cap_disconnect_req(conn, cmd, data);
2959 break;
2960
2961 case L2CAP_DISCONN_RSP:
2962 err = l2cap_disconnect_rsp(conn, cmd, data);
2963 break;
2964
2965 case L2CAP_ECHO_REQ:
2966 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
2967 break;
2968
2969 case L2CAP_ECHO_RSP:
2970 break;
2971
2972 case L2CAP_INFO_REQ:
2973 err = l2cap_information_req(conn, cmd, data);
2974 break;
2975
2976 case L2CAP_INFO_RSP:
2977 err = l2cap_information_rsp(conn, cmd, data);
2978 break;
2979
2980 default:
2981 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
2982 err = -EINVAL;
2983 break;
2984 }
2985
2986 return err;
2987}
2988
2989static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
2990 struct l2cap_cmd_hdr *cmd, u8 *data)
2991{
2992 switch (cmd->code) {
2993 case L2CAP_COMMAND_REJ:
2994 return 0;
2995
2996 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02002997 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002998
2999 case L2CAP_CONN_PARAM_UPDATE_RSP:
3000 return 0;
3001
3002 default:
3003 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3004 return -EINVAL;
3005 }
3006}
3007
3008static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3009 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010{
3011 u8 *data = skb->data;
3012 int len = skb->len;
3013 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003014 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015
3016 l2cap_raw_recv(conn, skb);
3017
3018 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003019 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3021 data += L2CAP_CMD_HDR_SIZE;
3022 len -= L2CAP_CMD_HDR_SIZE;
3023
Al Viro88219a02007-07-29 00:17:25 -07003024 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025
Al Viro88219a02007-07-29 00:17:25 -07003026 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 -07003027
Al Viro88219a02007-07-29 00:17:25 -07003028 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 BT_DBG("corrupted command");
3030 break;
3031 }
3032
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003033 if (conn->hcon->type == LE_LINK)
3034 err = l2cap_le_sig_cmd(conn, &cmd, data);
3035 else
3036 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037
3038 if (err) {
3039 struct l2cap_cmd_rej rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003040
3041 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042
3043 /* FIXME: Map err to a valid reason */
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07003044 rej.reason = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3046 }
3047
Al Viro88219a02007-07-29 00:17:25 -07003048 data += cmd_len;
3049 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 }
3051
3052 kfree_skb(skb);
3053}
3054
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003055static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003056{
3057 u16 our_fcs, rcv_fcs;
3058 int hdr_size = L2CAP_HDR_SIZE + 2;
3059
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003060 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003061 skb_trim(skb, skb->len - 2);
3062 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3063 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3064
3065 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003066 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003067 }
3068 return 0;
3069}
3070
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003071static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003072{
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003073 u16 control = 0;
3074
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003075 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003076
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003077 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
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. Padovan64988862010-05-10 14:54:14 -03003080 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003081 l2cap_send_sframe(chan, control);
3082 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003083 }
3084
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003085 if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
3086 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003087
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003088 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003089
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003090 if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003091 chan->frames_sent == 0) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003092 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003093 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003094 }
3095}
3096
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003097static 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 -03003098{
3099 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003100 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003101
3102 bt_cb(skb)->tx_seq = tx_seq;
3103 bt_cb(skb)->sar = sar;
3104
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003105 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003106 if (!next_skb) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003107 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003108 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003109 }
3110
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003111 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003112 if (tx_seq_offset < 0)
3113 tx_seq_offset += 64;
3114
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003115 do {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003116 if (bt_cb(next_skb)->tx_seq == tx_seq)
3117 return -EINVAL;
3118
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003119 next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003120 chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003121 if (next_tx_seq_offset < 0)
3122 next_tx_seq_offset += 64;
3123
3124 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003125 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003126 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003127 }
3128
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003129 if (skb_queue_is_last(&chan->srej_q, next_skb))
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003130 break;
3131
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003132 } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003133
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003134 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003135
3136 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003137}
3138
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003139static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003140{
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003141 struct sk_buff *_skb;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003142 int err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003143
3144 switch (control & L2CAP_CTRL_SAR) {
3145 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003146 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003147 goto drop;
3148
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003149 return chan->ops->recv(chan->data, skb);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003150
3151 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003152 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003153 goto drop;
3154
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003155 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003156
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003157 if (chan->sdu_len > chan->imtu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003158 goto disconnect;
3159
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003160 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3161 if (!chan->sdu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003162 return -ENOMEM;
3163
3164 /* pull sdu_len bytes only after alloc, because of Local Busy
3165 * condition we have to be sure that this will be executed
3166 * only once, i.e., when alloc does not fail */
3167 skb_pull(skb, 2);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003168
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003169 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003170
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003171 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003172 chan->partial_sdu_len = skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003173 break;
3174
3175 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003176 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003177 goto disconnect;
3178
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003179 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003180 goto disconnect;
3181
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003182 chan->partial_sdu_len += skb->len;
3183 if (chan->partial_sdu_len > chan->sdu_len)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003184 goto drop;
3185
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003186 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003187
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003188 break;
3189
3190 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003191 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003192 goto disconnect;
3193
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003194 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003195 goto disconnect;
3196
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003197 if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003198 chan->partial_sdu_len += skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003199
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003200 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003201 goto drop;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003202
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003203 if (chan->partial_sdu_len != chan->sdu_len)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003204 goto drop;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003205
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003206 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003207 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003208
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003209 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003210 if (!_skb) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003211 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003212 return -ENOMEM;
3213 }
3214
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003215 err = chan->ops->recv(chan->data, _skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003216 if (err < 0) {
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003217 kfree_skb(_skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003218 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003219 return err;
3220 }
3221
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003222 chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
3223 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003224
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003225 kfree_skb(chan->sdu);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003226 break;
3227 }
3228
3229 kfree_skb(skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003230 return 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003231
3232drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003233 kfree_skb(chan->sdu);
3234 chan->sdu = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003235
3236disconnect:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003237 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003238 kfree_skb(skb);
3239 return 0;
3240}
3241
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003242static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003243{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003244 struct sk_buff *skb;
3245 u16 control;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003246 int err;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003247
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003248 while ((skb = skb_dequeue(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003249 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003250 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003251 if (err < 0) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003252 skb_queue_head(&chan->busy_q, skb);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003253 return -EBUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003254 }
3255
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003256 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003257 }
3258
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003259 if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003260 goto done;
3261
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003262 control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003263 control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003264 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003265 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003266
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003267 __clear_retrans_timer(chan);
3268 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003269
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003270 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003271
3272done:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003273 chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
3274 chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003275
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003276 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003277
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003278 return 0;
3279}
3280
3281static void l2cap_busy_work(struct work_struct *work)
3282{
3283 DECLARE_WAITQUEUE(wait, current);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003284 struct l2cap_chan *chan =
3285 container_of(work, struct l2cap_chan, busy_work);
3286 struct sock *sk = chan->sk;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003287 int n_tries = 0, timeo = HZ/5, err;
3288 struct sk_buff *skb;
3289
3290 lock_sock(sk);
3291
3292 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003293 while ((skb = skb_peek(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003294 set_current_state(TASK_INTERRUPTIBLE);
3295
3296 if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
3297 err = -EBUSY;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003298 l2cap_send_disconn_req(chan->conn, chan, EBUSY);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003299 break;
3300 }
3301
3302 if (!timeo)
3303 timeo = HZ/5;
3304
3305 if (signal_pending(current)) {
3306 err = sock_intr_errno(timeo);
3307 break;
3308 }
3309
3310 release_sock(sk);
3311 timeo = schedule_timeout(timeo);
3312 lock_sock(sk);
3313
3314 err = sock_error(sk);
3315 if (err)
3316 break;
3317
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003318 if (l2cap_try_push_rx_skb(chan) == 0)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003319 break;
3320 }
3321
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003322 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02003323 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003324
3325 release_sock(sk);
3326}
3327
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003328static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003329{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003330 int sctrl, err;
3331
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003332 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003333 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003334 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003335 return l2cap_try_push_rx_skb(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003336
3337
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003338 }
3339
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003340 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003341 if (err >= 0) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003342 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003343 return err;
3344 }
3345
3346 /* Busy Condition */
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003347 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003348
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003349 chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003350 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003351 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003352
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003353 sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003354 sctrl |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003355 l2cap_send_sframe(chan, sctrl);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003356
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003357 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003358
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003359 __clear_ack_timer(chan);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003360
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003361 queue_work(_busy_wq, &chan->busy_work);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003362
3363 return err;
3364}
3365
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003366static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003367{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003368 struct sk_buff *_skb;
3369 int err = -EINVAL;
3370
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003371 /*
3372 * TODO: We have to notify the userland if some data is lost with the
3373 * Streaming Mode.
3374 */
3375
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003376 switch (control & L2CAP_CTRL_SAR) {
3377 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003378 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003379 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003380 break;
3381 }
3382
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003383 err = chan->ops->recv(chan->data, skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003384 if (!err)
3385 return 0;
3386
3387 break;
3388
3389 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003390 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003391 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003392 break;
3393 }
3394
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003395 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003396 skb_pull(skb, 2);
3397
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003398 if (chan->sdu_len > chan->imtu) {
Gustavo F. Padovan052897c2010-05-01 16:15:40 -03003399 err = -EMSGSIZE;
3400 break;
3401 }
3402
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003403 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3404 if (!chan->sdu) {
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003405 err = -ENOMEM;
3406 break;
3407 }
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. Padovan525cd182011-03-25 19:43:39 -03003411 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003412 chan->partial_sdu_len = skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003413 err = 0;
3414 break;
3415
3416 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003417 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003418 break;
3419
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003420 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003421
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003422 chan->partial_sdu_len += skb->len;
3423 if (chan->partial_sdu_len > chan->sdu_len)
3424 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003425 else
3426 err = 0;
3427
3428 break;
3429
3430 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003431 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003432 break;
3433
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003434 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003435
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003436 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003437 chan->partial_sdu_len += skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003438
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003439 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003440 goto drop;
3441
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003442 if (chan->partial_sdu_len == chan->sdu_len) {
3443 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003444 err = chan->ops->recv(chan->data, _skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003445 if (err < 0)
3446 kfree_skb(_skb);
3447 }
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003448 err = 0;
3449
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003450drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003451 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003452 break;
3453 }
3454
3455 kfree_skb(skb);
3456 return err;
3457}
3458
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003459static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003460{
3461 struct sk_buff *skb;
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003462 u16 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003463
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003464 while ((skb = skb_peek(&chan->srej_q))) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003465 if (bt_cb(skb)->tx_seq != tx_seq)
3466 break;
3467
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003468 skb = skb_dequeue(&chan->srej_q);
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003469 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003470 l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003471 chan->buffer_seq_srej =
3472 (chan->buffer_seq_srej + 1) % 64;
Gustavo F. Padovan8ff50ec2010-05-10 19:34:11 -03003473 tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003474 }
3475}
3476
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003477static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003478{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003479 struct srej_list *l, *tmp;
3480 u16 control;
3481
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003482 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003483 if (l->tx_seq == tx_seq) {
3484 list_del(&l->list);
3485 kfree(l);
3486 return;
3487 }
3488 control = L2CAP_SUPER_SELECT_REJECT;
3489 control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003490 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003491 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003492 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003493 }
3494}
3495
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003496static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003497{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003498 struct srej_list *new;
3499 u16 control;
3500
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003501 while (tx_seq != chan->expected_tx_seq) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003502 control = L2CAP_SUPER_SELECT_REJECT;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003503 control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003504 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003505
3506 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003507 new->tx_seq = chan->expected_tx_seq;
3508 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003509 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003510 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003511 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003512}
3513
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003514static 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 -03003515{
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003516 u8 tx_seq = __get_txseq(rx_control);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003517 u8 req_seq = __get_reqseq(rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003518 u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003519 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003520 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003521 int err = 0;
3522
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003523 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
3524 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003525
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003526 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003527 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003528 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003529 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003530 __set_retrans_timer(chan);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003531 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003532 }
3533
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003534 chan->expected_ack_seq = req_seq;
3535 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003536
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003537 if (tx_seq == chan->expected_tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003538 goto expected;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003539
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003540 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003541 if (tx_seq_offset < 0)
3542 tx_seq_offset += 64;
3543
3544 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003545 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003546 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003547 goto drop;
3548 }
3549
Mat Martineaue6949282011-06-03 16:21:10 -07003550 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003551 goto drop;
3552
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003553 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003554 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003555
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003556 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003557 struct srej_list, list);
3558 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003559 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003560 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003561
3562 list_del(&first->list);
3563 kfree(first);
3564
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003565 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003566 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003567 chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
3568 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003569 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003570 }
3571 } else {
3572 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003573
3574 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003575 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003576 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003577
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003578 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003579 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003580 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003581 return 0;
3582 }
3583 }
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003584 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003585 }
3586 } else {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003587 expected_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003588 (chan->expected_tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003589 if (expected_tx_seq_offset < 0)
3590 expected_tx_seq_offset += 64;
3591
3592 /* duplicated tx_seq */
3593 if (tx_seq_offset < expected_tx_seq_offset)
3594 goto drop;
3595
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003596 chan->conn_state |= L2CAP_CONN_SREJ_SENT;
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003597
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003598 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003599
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003600 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003601 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003602
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003603 __skb_queue_head_init(&chan->srej_q);
3604 __skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003605 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003606
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003607 chan->conn_state |= L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003608
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003609 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003610
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003611 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003612 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003613 return 0;
3614
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003615expected:
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003616 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003617
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003618 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003619 bt_cb(skb)->tx_seq = tx_seq;
3620 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003621 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003622 return 0;
3623 }
3624
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003625 err = l2cap_push_rx_skb(chan, skb, rx_control);
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003626 if (err < 0)
3627 return 0;
3628
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003629 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003630 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3631 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003632 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003633 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003634 }
3635
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003636 __set_ack_timer(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003637
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003638 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3639 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003640 l2cap_send_ack(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003641
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003642 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003643
3644drop:
3645 kfree_skb(skb);
3646 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003647}
3648
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003649static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003650{
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003651 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003652 rx_control);
3653
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003654 chan->expected_ack_seq = __get_reqseq(rx_control);
3655 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003656
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003657 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003658 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3659 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
3660 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003661 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003662 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003663
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003664 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3665 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003666 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003667 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003668 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003669
3670 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003671 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003672
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003673 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3674 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003675 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003676 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003677
3678 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003679 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003680 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003681 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003682
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003683 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3684 if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
3685 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003686 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003687 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003688 }
3689}
3690
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003691static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003692{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003693 u8 tx_seq = __get_reqseq(rx_control);
3694
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003695 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003696
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003697 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003698
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003699 chan->expected_ack_seq = tx_seq;
3700 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003701
3702 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003703 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3704 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003705 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003706 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003707 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003708 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003709
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003710 if (chan->conn_state & L2CAP_CONN_WAIT_F)
3711 chan->conn_state |= L2CAP_CONN_REJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003712 }
3713}
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003714static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003715{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003716 u8 tx_seq = __get_reqseq(rx_control);
3717
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003718 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003719
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003720 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003721
3722 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003723 chan->expected_ack_seq = tx_seq;
3724 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003725
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003726 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3727 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003728
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003729 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003730
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003731 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003732 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003733 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003734 }
3735 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003736 if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003737 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003738 chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003739 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003740 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003741 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003742 l2cap_retransmit_one_frame(chan, tx_seq);
3743 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003744 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003745 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003746 }
3747 }
3748}
3749
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003750static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003751{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003752 u8 tx_seq = __get_reqseq(rx_control);
3753
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003754 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003755
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003756 chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003757 chan->expected_ack_seq = tx_seq;
3758 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003759
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003760 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003761 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003762
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003763 if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003764 __clear_retrans_timer(chan);
Gustavo F. Padovana2e12a22010-05-05 19:58:27 -03003765 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003766 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003767 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003768 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003769
3770 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003771 l2cap_send_srejtail(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003772 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003773 l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003774}
3775
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003776static 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 -03003777{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003778 BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003779
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003780 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003781 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003782 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003783 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003784 __set_retrans_timer(chan);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003785 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003786 }
3787
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003788 switch (rx_control & L2CAP_CTRL_SUPERVISE) {
3789 case L2CAP_SUPER_RCV_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003790 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003791 break;
3792
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003793 case L2CAP_SUPER_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003794 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003795 break;
3796
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003797 case L2CAP_SUPER_SELECT_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003798 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003799 break;
3800
3801 case L2CAP_SUPER_RCV_NOT_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003802 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003803 break;
3804 }
3805
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03003806 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003807 return 0;
3808}
3809
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003810static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
3811{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003812 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003813 u16 control;
3814 u8 req_seq;
3815 int len, next_tx_seq_offset, req_seq_offset;
3816
3817 control = get_unaligned_le16(skb->data);
3818 skb_pull(skb, 2);
3819 len = skb->len;
3820
3821 /*
3822 * We can just drop the corrupted I-frame here.
3823 * Receiver will miss it and start proper recovery
3824 * procedures and ask retransmission.
3825 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003826 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003827 goto drop;
3828
3829 if (__is_sar_start(control) && __is_iframe(control))
3830 len -= 2;
3831
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003832 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003833 len -= 2;
3834
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003835 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003836 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003837 goto drop;
3838 }
3839
3840 req_seq = __get_reqseq(control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003841 req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003842 if (req_seq_offset < 0)
3843 req_seq_offset += 64;
3844
3845 next_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003846 (chan->next_tx_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003847 if (next_tx_seq_offset < 0)
3848 next_tx_seq_offset += 64;
3849
3850 /* check for invalid req-seq */
3851 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003852 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003853 goto drop;
3854 }
3855
3856 if (__is_iframe(control)) {
3857 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003858 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003859 goto drop;
3860 }
3861
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003862 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003863 } else {
3864 if (len != 0) {
3865 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003866 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003867 goto drop;
3868 }
3869
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003870 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003871 }
3872
3873 return 0;
3874
3875drop:
3876 kfree_skb(skb);
3877 return 0;
3878}
3879
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
3881{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003882 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07003883 struct sock *sk = NULL;
Nathan Holstein51893f82010-06-09 15:46:25 -04003884 u16 control;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003885 u8 tx_seq;
3886 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003887
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003888 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003889 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003890 BT_DBG("unknown cid 0x%4.4x", cid);
3891 goto drop;
3892 }
3893
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003894 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003895
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003896 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003898 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 goto drop;
3900
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003901 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003902 case L2CAP_MODE_BASIC:
3903 /* If socket recv buffers overflows we drop data here
3904 * which is *bad* because L2CAP has to be reliable.
3905 * But we don't have any other choice. L2CAP doesn't
3906 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003907
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003908 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003909 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003911 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003912 goto done;
3913 break;
3914
3915 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003916 if (!sock_owned_by_user(sk)) {
3917 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003918 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003919 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003920 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003921 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003922
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02003923 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003924
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003925 case L2CAP_MODE_STREAMING:
3926 control = get_unaligned_le16(skb->data);
3927 skb_pull(skb, 2);
3928 len = skb->len;
3929
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003930 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03003931 goto drop;
3932
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003933 if (__is_sar_start(control))
3934 len -= 2;
3935
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003936 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003937 len -= 2;
3938
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003939 if (len > chan->mps || len < 0 || __is_sframe(control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003940 goto drop;
3941
3942 tx_seq = __get_txseq(control);
3943
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003944 if (chan->expected_tx_seq == tx_seq)
3945 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003946 else
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003947 chan->expected_tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003948
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003949 l2cap_streaming_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003950
3951 goto done;
3952
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003953 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003954 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003955 break;
3956 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957
3958drop:
3959 kfree_skb(skb);
3960
3961done:
Marcel Holtmann01394182006-07-03 10:02:46 +02003962 if (sk)
3963 bh_unlock_sock(sk);
3964
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 return 0;
3966}
3967
Al Viro8e036fc2007-07-29 00:16:36 -07003968static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003970 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003971 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003973 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
3974 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 goto drop;
3976
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003977 sk = chan->sk;
3978
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00003979 bh_lock_sock(sk);
3980
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 BT_DBG("sk %p, len %d", sk, skb->len);
3982
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003983 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 goto drop;
3985
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003986 if (l2cap_pi(sk)->chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 goto drop;
3988
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003989 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 goto done;
3991
3992drop:
3993 kfree_skb(skb);
3994
3995done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03003996 if (sk)
3997 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 return 0;
3999}
4000
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004001static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4002{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004003 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004004 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004005
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004006 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4007 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004008 goto drop;
4009
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004010 sk = chan->sk;
4011
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004012 bh_lock_sock(sk);
4013
4014 BT_DBG("sk %p, len %d", sk, skb->len);
4015
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004016 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004017 goto drop;
4018
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004019 if (l2cap_pi(sk)->chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004020 goto drop;
4021
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004022 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004023 goto done;
4024
4025drop:
4026 kfree_skb(skb);
4027
4028done:
4029 if (sk)
4030 bh_unlock_sock(sk);
4031 return 0;
4032}
4033
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4035{
4036 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004037 u16 cid, len;
4038 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039
4040 skb_pull(skb, L2CAP_HDR_SIZE);
4041 cid = __le16_to_cpu(lh->cid);
4042 len = __le16_to_cpu(lh->len);
4043
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004044 if (len != skb->len) {
4045 kfree_skb(skb);
4046 return;
4047 }
4048
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4050
4051 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004052 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004053 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054 l2cap_sig_channel(conn, skb);
4055 break;
4056
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004057 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004058 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 skb_pull(skb, 2);
4060 l2cap_conless_channel(conn, psm, skb);
4061 break;
4062
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004063 case L2CAP_CID_LE_DATA:
4064 l2cap_att_channel(conn, cid, skb);
4065 break;
4066
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004067 case L2CAP_CID_SMP:
4068 if (smp_sig_channel(conn, skb))
4069 l2cap_conn_del(conn->hcon, EACCES);
4070 break;
4071
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 default:
4073 l2cap_data_channel(conn, cid, skb);
4074 break;
4075 }
4076}
4077
4078/* ---- L2CAP interface with lower layer (HCI) ---- */
4079
4080static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4081{
4082 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004083 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084
4085 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004086 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087
4088 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4089
4090 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004091 read_lock(&chan_list_lock);
4092 list_for_each_entry(c, &chan_list, global_l) {
4093 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004094
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004095 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 continue;
4097
4098 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004099 lm1 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004100 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004101 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004103 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4104 lm2 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004105 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004106 lm2 |= HCI_LM_MASTER;
4107 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004109 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110
4111 return exact ? lm1 : lm2;
4112}
4113
4114static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4115{
Marcel Holtmann01394182006-07-03 10:02:46 +02004116 struct l2cap_conn *conn;
4117
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4119
Ville Tervoacd7d372011-02-10 22:38:49 -03004120 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004121 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122
4123 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124 conn = l2cap_conn_add(hcon, status);
4125 if (conn)
4126 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004127 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 l2cap_conn_del(hcon, bt_err(status));
4129
4130 return 0;
4131}
4132
Marcel Holtmann2950f212009-02-12 14:02:50 +01004133static int l2cap_disconn_ind(struct hci_conn *hcon)
4134{
4135 struct l2cap_conn *conn = hcon->l2cap_data;
4136
4137 BT_DBG("hcon %p", hcon);
4138
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004139 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004140 return 0x13;
4141
4142 return conn->disc_reason;
4143}
4144
4145static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146{
4147 BT_DBG("hcon %p reason %d", hcon, reason);
4148
Ville Tervoacd7d372011-02-10 22:38:49 -03004149 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004150 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151
4152 l2cap_conn_del(hcon, bt_err(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004153
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 return 0;
4155}
4156
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004157static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004158{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004159 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004160 return;
4161
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004162 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004163 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004164 __clear_chan_timer(chan);
4165 __set_chan_timer(chan, HZ * 5);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004166 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004167 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004168 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004169 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004170 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004171 }
4172}
4173
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004174static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004176 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004177 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178
Marcel Holtmann01394182006-07-03 10:02:46 +02004179 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004181
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 BT_DBG("conn %p", conn);
4183
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004184 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004186 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004187 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004188
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189 bh_lock_sock(sk);
4190
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004191 if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004192 bh_unlock_sock(sk);
4193 continue;
4194 }
4195
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004196 if (!status && (chan->state == BT_CONNECTED ||
4197 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004198 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004199 bh_unlock_sock(sk);
4200 continue;
4201 }
4202
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004203 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004204 if (!status) {
4205 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004206 req.scid = cpu_to_le16(chan->scid);
4207 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004208
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004209 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004210 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004211
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004212 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004213 L2CAP_CONN_REQ, sizeof(req), &req);
4214 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004215 __clear_chan_timer(chan);
4216 __set_chan_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004217 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004218 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004219 struct l2cap_conn_rsp rsp;
4220 __u16 result;
4221
4222 if (!status) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004223 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004224 result = L2CAP_CR_SUCCESS;
4225 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004226 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004227 __set_chan_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004228 result = L2CAP_CR_SEC_BLOCK;
4229 }
4230
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004231 rsp.scid = cpu_to_le16(chan->dcid);
4232 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004233 rsp.result = cpu_to_le16(result);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02004234 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004235 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4236 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 }
4238
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 bh_unlock_sock(sk);
4240 }
4241
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004242 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004243
Linus Torvalds1da177e2005-04-16 15:20:36 -07004244 return 0;
4245}
4246
4247static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4248{
4249 struct l2cap_conn *conn = hcon->l2cap_data;
4250
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004251 if (!conn)
4252 conn = l2cap_conn_add(hcon, 0);
4253
4254 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 goto drop;
4256
4257 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4258
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004259 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004260 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004261 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004262 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 int len;
4264
4265 if (conn->rx_len) {
4266 BT_ERR("Unexpected start frame (len %d)", skb->len);
4267 kfree_skb(conn->rx_skb);
4268 conn->rx_skb = NULL;
4269 conn->rx_len = 0;
4270 l2cap_conn_unreliable(conn, ECOMM);
4271 }
4272
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004273 /* Start fragment always begin with Basic L2CAP header */
4274 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 BT_ERR("Frame is too short (len %d)", skb->len);
4276 l2cap_conn_unreliable(conn, ECOMM);
4277 goto drop;
4278 }
4279
4280 hdr = (struct l2cap_hdr *) skb->data;
4281 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004282 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283
4284 if (len == skb->len) {
4285 /* Complete frame received */
4286 l2cap_recv_frame(conn, skb);
4287 return 0;
4288 }
4289
4290 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4291
4292 if (skb->len > len) {
4293 BT_ERR("Frame is too long (len %d, expected len %d)",
4294 skb->len, len);
4295 l2cap_conn_unreliable(conn, ECOMM);
4296 goto drop;
4297 }
4298
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004299 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004300
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004301 if (chan && chan->sk) {
4302 struct sock *sk = chan->sk;
4303
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004304 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004305 BT_ERR("Frame exceeding recv MTU (len %d, "
4306 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004307 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004308 bh_unlock_sock(sk);
4309 l2cap_conn_unreliable(conn, ECOMM);
4310 goto drop;
4311 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004312 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004313 }
4314
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004316 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4317 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 goto drop;
4319
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004320 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004321 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 conn->rx_len = len - skb->len;
4323 } else {
4324 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4325
4326 if (!conn->rx_len) {
4327 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4328 l2cap_conn_unreliable(conn, ECOMM);
4329 goto drop;
4330 }
4331
4332 if (skb->len > conn->rx_len) {
4333 BT_ERR("Fragment is too long (len %d, expected %d)",
4334 skb->len, conn->rx_len);
4335 kfree_skb(conn->rx_skb);
4336 conn->rx_skb = NULL;
4337 conn->rx_len = 0;
4338 l2cap_conn_unreliable(conn, ECOMM);
4339 goto drop;
4340 }
4341
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004342 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004343 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 conn->rx_len -= skb->len;
4345
4346 if (!conn->rx_len) {
4347 /* Complete frame received */
4348 l2cap_recv_frame(conn, conn->rx_skb);
4349 conn->rx_skb = NULL;
4350 }
4351 }
4352
4353drop:
4354 kfree_skb(skb);
4355 return 0;
4356}
4357
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004358static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004360 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004361
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004362 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004364 list_for_each_entry(c, &chan_list, global_l) {
4365 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004366
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004367 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 +01004368 batostr(&bt_sk(sk)->src),
4369 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004370 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004371 c->scid, c->dcid, c->imtu, c->omtu,
4372 c->sec_level, c->mode);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004373 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004375 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004376
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004377 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378}
4379
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004380static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4381{
4382 return single_open(file, l2cap_debugfs_show, inode->i_private);
4383}
4384
4385static const struct file_operations l2cap_debugfs_fops = {
4386 .open = l2cap_debugfs_open,
4387 .read = seq_read,
4388 .llseek = seq_lseek,
4389 .release = single_release,
4390};
4391
4392static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394static struct hci_proto l2cap_hci_proto = {
4395 .name = "L2CAP",
4396 .id = HCI_PROTO_L2CAP,
4397 .connect_ind = l2cap_connect_ind,
4398 .connect_cfm = l2cap_connect_cfm,
4399 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004400 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004401 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 .recv_acldata = l2cap_recv_acldata
4403};
4404
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004405int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406{
4407 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004408
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004409 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 if (err < 0)
4411 return err;
4412
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004413 _busy_wq = create_singlethread_workqueue("l2cap");
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004414 if (!_busy_wq) {
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004415 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 goto error;
4417 }
4418
4419 err = hci_register_proto(&l2cap_hci_proto);
4420 if (err < 0) {
4421 BT_ERR("L2CAP protocol registration failed");
4422 bt_sock_unregister(BTPROTO_L2CAP);
4423 goto error;
4424 }
4425
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004426 if (bt_debugfs) {
4427 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4428 bt_debugfs, NULL, &l2cap_debugfs_fops);
4429 if (!l2cap_debugfs)
4430 BT_ERR("Failed to create L2CAP debug file");
4431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433 return 0;
4434
4435error:
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004436 destroy_workqueue(_busy_wq);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004437 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 return err;
4439}
4440
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004441void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004443 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004445 flush_workqueue(_busy_wq);
4446 destroy_workqueue(_busy_wq);
4447
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4449 BT_ERR("L2CAP protocol unregistration failed");
4450
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004451 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452}
4453
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004454module_param(disable_ertm, bool, 0644);
4455MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");