blob: bbbae2e0aa8472bcad3ee49278e360565a161337 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
7 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation;
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090017 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090022 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 SOFTWARE IS DISCLAIMED.
25*/
26
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020027/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30
31#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/sched.h>
36#include <linux/slab.h>
37#include <linux/poll.h>
38#include <linux/fcntl.h>
39#include <linux/init.h>
40#include <linux/interrupt.h>
41#include <linux/socket.h>
42#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080044#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010045#include <linux/debugfs.h>
46#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030047#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030048#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/sock.h>
50
51#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/unaligned.h>
53
54#include <net/bluetooth/bluetooth.h>
55#include <net/bluetooth/hci_core.h>
56#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030057#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020059int disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020060
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070061static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Marcel Holtmanne1027a72009-02-09 09:18:02 +010062static u8 l2cap_fixed_chan[8] = { 0x02, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Gustavo F. Padovan1890d362010-05-01 16:15:44 -030064static struct workqueue_struct *_busy_wq;
65
Johannes Bergb5ad8b72011-06-01 08:54:45 +020066static LIST_HEAD(chan_list);
67static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Gustavo F. Padovan1890d362010-05-01 16:15:44 -030069static void l2cap_busy_work(struct work_struct *work);
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
72 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030073static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
74 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030075static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030076static void l2cap_send_disconn_req(struct l2cap_conn *conn,
77 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030079static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
80
Marcel Holtmann01394182006-07-03 10:02:46 +020081/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030082
83static inline void chan_hold(struct l2cap_chan *c)
84{
85 atomic_inc(&c->refcnt);
86}
87
88static inline void chan_put(struct l2cap_chan *c)
89{
90 if (atomic_dec_and_test(&c->refcnt))
91 kfree(c);
92}
93
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030094static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020095{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030096 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030097
98 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030099 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300100 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200101 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300102 return NULL;
103
Marcel Holtmann01394182006-07-03 10:02:46 +0200104}
105
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300106static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200107{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300108 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300109
110 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300111 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300112 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200113 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300114 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200115}
116
117/* Find channel with given SCID.
118 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300119static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200120{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300121 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300122
123 read_lock(&conn->chan_lock);
124 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300125 if (c)
126 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300127 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300128 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200129}
130
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300131static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200132{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300133 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300134
135 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300136 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300137 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200138 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300139 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200140}
141
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300142static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200143{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300144 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300145
146 read_lock(&conn->chan_lock);
147 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300148 if (c)
149 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300150 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300151 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200152}
153
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300154static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300155{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300156 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300157
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300158 list_for_each_entry(c, &chan_list, global_l) {
159 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300160 goto found;
161 }
162
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300163 c = NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300164found:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300165 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300166}
167
168int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
169{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300170 int err;
171
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300172 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300173
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300174 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300175 err = -EADDRINUSE;
176 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300177 }
178
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300179 if (psm) {
180 chan->psm = psm;
181 chan->sport = psm;
182 err = 0;
183 } else {
184 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300185
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300186 err = -EINVAL;
187 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300188 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300189 chan->psm = cpu_to_le16(p);
190 chan->sport = cpu_to_le16(p);
191 err = 0;
192 break;
193 }
194 }
195
196done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300197 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300198 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300199}
200
201int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
202{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300203 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300204
205 chan->scid = scid;
206
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300207 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300208
209 return 0;
210}
211
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300212static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200213{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300214 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200215
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300216 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300217 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200218 return cid;
219 }
220
221 return 0;
222}
223
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300224static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300225{
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300226 BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
227
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300228 if (!mod_timer(timer, jiffies + timeout))
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300229 chan_hold(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300230}
231
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300232static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300233{
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300234 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300235
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300236 if (timer_pending(timer) && del_timer(timer))
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300237 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300238}
239
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300240static void l2cap_state_change(struct l2cap_chan *chan, int state)
241{
242 chan->state = state;
243 chan->ops->state_change(chan->data, state);
244}
245
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300246static void l2cap_chan_timeout(unsigned long arg)
247{
248 struct l2cap_chan *chan = (struct l2cap_chan *) arg;
249 struct sock *sk = chan->sk;
250 int reason;
251
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300252 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300253
254 bh_lock_sock(sk);
255
256 if (sock_owned_by_user(sk)) {
257 /* sk is owned by user. Try again later */
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300258 __set_chan_timer(chan, HZ / 5);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300259 bh_unlock_sock(sk);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300260 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300261 return;
262 }
263
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300264 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300265 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300266 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300267 chan->sec_level != BT_SECURITY_SDP)
268 reason = ECONNREFUSED;
269 else
270 reason = ETIMEDOUT;
271
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300272 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300273
274 bh_unlock_sock(sk);
275
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300276 chan->ops->close(chan->data);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300277 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300278}
279
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300280struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200281{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300282 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200283
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300284 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
285 if (!chan)
286 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200287
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300288 chan->sk = sk;
289
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300290 write_lock_bh(&chan_list_lock);
291 list_add(&chan->global_l, &chan_list);
292 write_unlock_bh(&chan_list_lock);
293
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300294 setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
295
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300296 chan->state = BT_OPEN;
297
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300298 atomic_set(&chan->refcnt, 1);
299
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300300 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200301}
302
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300303void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300304{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300305 write_lock_bh(&chan_list_lock);
306 list_del(&chan->global_l);
307 write_unlock_bh(&chan_list_lock);
308
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300309 chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300310}
311
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300312static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200313{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300314 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300315 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200316
Marcel Holtmann2950f212009-02-12 14:02:50 +0100317 conn->disc_reason = 0x13;
318
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300319 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200320
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300321 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300322 if (conn->hcon->type == LE_LINK) {
323 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300324 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300325 chan->scid = L2CAP_CID_LE_DATA;
326 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300327 } else {
328 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300329 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300330 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300331 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300332 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200333 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300334 chan->scid = L2CAP_CID_CONN_LESS;
335 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300336 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200337 } else {
338 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300339 chan->scid = L2CAP_CID_SIGNALING;
340 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300341 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200342 }
343
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300344 chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300345
346 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200347}
348
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900349/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200350 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300351static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200352{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300353 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300354 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200355 struct sock *parent = bt_sk(sk)->parent;
356
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300357 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200358
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300359 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200360
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900361 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300362 /* Delete from channel list */
363 write_lock_bh(&conn->chan_lock);
364 list_del(&chan->list);
365 write_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300366 chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300367
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300368 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200369 hci_conn_put(conn->hcon);
370 }
371
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300372 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200373 sock_set_flag(sk, SOCK_ZAPPED);
374
375 if (err)
376 sk->sk_err = err;
377
378 if (parent) {
379 bt_accept_unlink(sk);
380 parent->sk_data_ready(parent, 0);
381 } else
382 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300383
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300384 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE &&
385 chan->conf_state & L2CAP_CONF_INPUT_DONE))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300386 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300387
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300388 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300389
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300390 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300391 struct srej_list *l, *tmp;
392
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300393 __clear_retrans_timer(chan);
394 __clear_monitor_timer(chan);
395 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300396
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300397 skb_queue_purge(&chan->srej_q);
398 skb_queue_purge(&chan->busy_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300399
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300400 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300401 list_del(&l->list);
402 kfree(l);
403 }
404 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200405}
406
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300407static void l2cap_chan_cleanup_listen(struct sock *parent)
408{
409 struct sock *sk;
410
411 BT_DBG("parent %p", parent);
412
413 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300414 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300415 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300416 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300417 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300418 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300419 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300420 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300421 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300422}
423
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300424void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300425{
426 struct l2cap_conn *conn = chan->conn;
427 struct sock *sk = chan->sk;
428
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300429 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300430
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300431 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300432 case BT_LISTEN:
433 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300434
435 l2cap_state_change(chan, BT_CLOSED);
436 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300437 break;
438
439 case BT_CONNECTED:
440 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300441 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300442 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300443 __clear_chan_timer(chan);
444 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300445 l2cap_send_disconn_req(conn, chan, reason);
446 } else
447 l2cap_chan_del(chan, reason);
448 break;
449
450 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300451 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300452 conn->hcon->type == ACL_LINK) {
453 struct l2cap_conn_rsp rsp;
454 __u16 result;
455
456 if (bt_sk(sk)->defer_setup)
457 result = L2CAP_CR_SEC_BLOCK;
458 else
459 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300460 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300461
462 rsp.scid = cpu_to_le16(chan->dcid);
463 rsp.dcid = cpu_to_le16(chan->scid);
464 rsp.result = cpu_to_le16(result);
465 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
466 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
467 sizeof(rsp), &rsp);
468 }
469
470 l2cap_chan_del(chan, reason);
471 break;
472
473 case BT_CONNECT:
474 case BT_DISCONN:
475 l2cap_chan_del(chan, reason);
476 break;
477
478 default:
479 sock_set_flag(sk, SOCK_ZAPPED);
480 break;
481 }
482}
483
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300484static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530485{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300486 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300487 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530488 case BT_SECURITY_HIGH:
489 return HCI_AT_DEDICATED_BONDING_MITM;
490 case BT_SECURITY_MEDIUM:
491 return HCI_AT_DEDICATED_BONDING;
492 default:
493 return HCI_AT_NO_BONDING;
494 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300495 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300496 if (chan->sec_level == BT_SECURITY_LOW)
497 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530498
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300499 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530500 return HCI_AT_NO_BONDING_MITM;
501 else
502 return HCI_AT_NO_BONDING;
503 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300504 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530505 case BT_SECURITY_HIGH:
506 return HCI_AT_GENERAL_BONDING_MITM;
507 case BT_SECURITY_MEDIUM:
508 return HCI_AT_GENERAL_BONDING;
509 default:
510 return HCI_AT_NO_BONDING;
511 }
512 }
513}
514
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200515/* Service level security */
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300516static inline int l2cap_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200517{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300518 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100519 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200520
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300521 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100522
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300523 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200524}
525
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200526static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200527{
528 u8 id;
529
530 /* Get next available identificator.
531 * 1 - 128 are used by kernel.
532 * 129 - 199 are reserved.
533 * 200 - 254 are used by utilities like l2ping, etc.
534 */
535
536 spin_lock_bh(&conn->lock);
537
538 if (++conn->tx_ident > 128)
539 conn->tx_ident = 1;
540
541 id = conn->tx_ident;
542
543 spin_unlock_bh(&conn->lock);
544
545 return id;
546}
547
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300548static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200549{
550 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200551 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200552
553 BT_DBG("code 0x%2.2x", code);
554
555 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300556 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200557
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200558 if (lmp_no_flush_capable(conn->hcon->hdev))
559 flags = ACL_START_NO_FLUSH;
560 else
561 flags = ACL_START;
562
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700563 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
564
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200565 hci_send_acl(conn->hcon, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200566}
567
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300568static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300569{
570 struct sk_buff *skb;
571 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300572 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300573 int count, hlen = L2CAP_HDR_SIZE + 2;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200574 u8 flags;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300575
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300576 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300577 return;
578
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300579 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300580 hlen += 2;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300581
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300582 BT_DBG("chan %p, control 0x%2.2x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300583
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300584 count = min_t(unsigned int, conn->mtu, hlen);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300585 control |= L2CAP_CTRL_FRAME_TYPE;
586
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300587 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300588 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300589 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300590 }
591
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300592 if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300593 control |= L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300594 chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300595 }
596
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300597 skb = bt_skb_alloc(count, GFP_ATOMIC);
598 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300599 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300600
601 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300602 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300603 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300604 put_unaligned_le16(control, skb_put(skb, 2));
605
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300606 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300607 u16 fcs = crc16(0, (u8 *)lh, count - 2);
608 put_unaligned_le16(fcs, skb_put(skb, 2));
609 }
610
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200611 if (lmp_no_flush_capable(conn->hcon->hdev))
612 flags = ACL_START_NO_FLUSH;
613 else
614 flags = ACL_START;
615
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700616 bt_cb(skb)->force_active = chan->force_active;
617
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300618 hci_send_acl(chan->conn->hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300619}
620
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300621static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300622{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300623 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300624 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300625 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300626 } else
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300627 control |= L2CAP_SUPER_RCV_READY;
628
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -0300629 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300630
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300631 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300632}
633
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300634static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300635{
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300636 return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300637}
638
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300639static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200640{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300641 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200642
643 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100644 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
645 return;
646
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300647 if (l2cap_check_security(chan) &&
648 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200649 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300650 req.scid = cpu_to_le16(chan->scid);
651 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200652
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300653 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300654 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200655
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300656 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
657 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200658 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200659 } else {
660 struct l2cap_info_req req;
661 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
662
663 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
664 conn->info_ident = l2cap_get_ident(conn);
665
666 mod_timer(&conn->info_timer, jiffies +
667 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
668
669 l2cap_send_cmd(conn, conn->info_ident,
670 L2CAP_INFO_REQ, sizeof(req), &req);
671 }
672}
673
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300674static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
675{
676 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300677 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300678 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
679
680 switch (mode) {
681 case L2CAP_MODE_ERTM:
682 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
683 case L2CAP_MODE_STREAMING:
684 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
685 default:
686 return 0x00;
687 }
688}
689
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300690static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300691{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300692 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300693 struct l2cap_disconn_req req;
694
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300695 if (!conn)
696 return;
697
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300698 sk = chan->sk;
699
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300700 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300701 __clear_retrans_timer(chan);
702 __clear_monitor_timer(chan);
703 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300704 }
705
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300706 req.dcid = cpu_to_le16(chan->dcid);
707 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300708 l2cap_send_cmd(conn, l2cap_get_ident(conn),
709 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300710
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300711 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300712 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300713}
714
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200716static void l2cap_conn_start(struct l2cap_conn *conn)
717{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300718 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200719
720 BT_DBG("conn %p", conn);
721
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300722 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200723
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300724 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300725 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300726
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200727 bh_lock_sock(sk);
728
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300729 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200730 bh_unlock_sock(sk);
731 continue;
732 }
733
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300734 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300735 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300736
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300737 if (!l2cap_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300738 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300739 bh_unlock_sock(sk);
740 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200741 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300742
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300743 if (!l2cap_mode_supported(chan->mode,
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300744 conn->feat_mask)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300745 && chan->conf_state &
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300746 L2CAP_CONF_STATE2_DEVICE) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300747 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300748 * so release the lock */
749 read_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300750 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300751 read_lock_bh(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300752 bh_unlock_sock(sk);
753 continue;
754 }
755
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300756 req.scid = cpu_to_le16(chan->scid);
757 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300758
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300759 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300760 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300761
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300762 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
763 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300764
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300765 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200766 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300767 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300768 rsp.scid = cpu_to_le16(chan->dcid);
769 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200770
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300771 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100772 if (bt_sk(sk)->defer_setup) {
773 struct sock *parent = bt_sk(sk)->parent;
774 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
775 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
776 parent->sk_data_ready(parent, 0);
777
778 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300779 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100780 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
781 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
782 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200783 } else {
784 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
785 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
786 }
787
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300788 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
789 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300790
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300791 if (chan->conf_state & L2CAP_CONF_REQ_SENT ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300792 rsp.result != L2CAP_CR_SUCCESS) {
793 bh_unlock_sock(sk);
794 continue;
795 }
796
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300797 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300798 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300799 l2cap_build_conf_req(chan, buf), buf);
800 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200801 }
802
803 bh_unlock_sock(sk);
804 }
805
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300806 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200807}
808
Ville Tervob62f3282011-02-10 22:38:50 -0300809/* Find socket with cid and source bdaddr.
810 * Returns closest match, locked.
811 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300812static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300813{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300814 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300815
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300816 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300817
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300818 list_for_each_entry(c, &chan_list, global_l) {
819 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300820
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300821 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300822 continue;
823
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300824 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300825 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300826 if (!bacmp(&bt_sk(sk)->src, src)) {
827 read_unlock(&chan_list_lock);
828 return c;
829 }
Ville Tervob62f3282011-02-10 22:38:50 -0300830
831 /* Closest match */
832 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300833 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300834 }
835 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300836
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300837 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300838
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300839 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300840}
841
842static void l2cap_le_conn_ready(struct l2cap_conn *conn)
843{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300844 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300845 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300846
847 BT_DBG("");
848
849 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300850 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300851 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300852 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300853 return;
854
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300855 parent = pchan->sk;
856
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300857 bh_lock_sock(parent);
858
Ville Tervob62f3282011-02-10 22:38:50 -0300859 /* Check for backlog size */
860 if (sk_acceptq_is_full(parent)) {
861 BT_DBG("backlog full %d", parent->sk_ack_backlog);
862 goto clean;
863 }
864
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300865 chan = pchan->ops->new_connection(pchan->data);
866 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300867 goto clean;
868
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300869 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300870
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300871 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300872
873 hci_conn_hold(conn->hcon);
874
Ville Tervob62f3282011-02-10 22:38:50 -0300875 bacpy(&bt_sk(sk)->src, conn->src);
876 bacpy(&bt_sk(sk)->dst, conn->dst);
877
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300878 bt_accept_enqueue(parent, sk);
879
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300880 __l2cap_chan_add(conn, chan);
881
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300882 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300883
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300884 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300885 parent->sk_data_ready(parent, 0);
886
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300887 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300888
889clean:
890 bh_unlock_sock(parent);
891}
892
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300893static void l2cap_chan_ready(struct sock *sk)
894{
895 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
896 struct sock *parent = bt_sk(sk)->parent;
897
898 BT_DBG("sk %p, parent %p", sk, parent);
899
900 chan->conf_state = 0;
901 __clear_chan_timer(chan);
902
903 sk->sk_state = BT_CONNECTED;
904 sk->sk_state_change(sk);
905
906 if (parent)
907 parent->sk_data_ready(parent, 0);
908}
909
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200910static void l2cap_conn_ready(struct l2cap_conn *conn)
911{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300912 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200913
914 BT_DBG("conn %p", conn);
915
Ville Tervob62f3282011-02-10 22:38:50 -0300916 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
917 l2cap_le_conn_ready(conn);
918
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300919 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200920
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300921 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300922 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300923
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200924 bh_lock_sock(sk);
925
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300926 if (conn->hcon->type == LE_LINK)
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300927 if (smp_conn_security(conn, chan->sec_level))
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300928 l2cap_chan_ready(sk);
Ville Tervoacd7d372011-02-10 22:38:49 -0300929
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300930 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300931 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300932 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200933 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300934
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300935 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300936 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200937
938 bh_unlock_sock(sk);
939 }
940
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300941 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200942}
943
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200944/* Notify sockets that we cannot guaranty reliability anymore */
945static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
946{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300947 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200948
949 BT_DBG("conn %p", conn);
950
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300951 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200952
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300953 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300954 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300955
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300956 if (chan->force_reliable)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200957 sk->sk_err = err;
958 }
959
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300960 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200961}
962
963static void l2cap_info_timeout(unsigned long arg)
964{
965 struct l2cap_conn *conn = (void *) arg;
966
Marcel Holtmann984947d2009-02-06 23:35:19 +0100967 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100968 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100969
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200970 l2cap_conn_start(conn);
971}
972
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300973static void l2cap_conn_del(struct hci_conn *hcon, int err)
974{
975 struct l2cap_conn *conn = hcon->l2cap_data;
976 struct l2cap_chan *chan, *l;
977 struct sock *sk;
978
979 if (!conn)
980 return;
981
982 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
983
984 kfree_skb(conn->rx_skb);
985
986 /* Kill channels */
987 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
988 sk = chan->sk;
989 bh_lock_sock(sk);
990 l2cap_chan_del(chan, err);
991 bh_unlock_sock(sk);
992 chan->ops->close(chan->data);
993 }
994
995 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
996 del_timer_sync(&conn->info_timer);
997
998 if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
999 del_timer(&conn->security_timer);
1000
1001 hcon->l2cap_data = NULL;
1002 kfree(conn);
1003}
1004
1005static void security_timeout(unsigned long arg)
1006{
1007 struct l2cap_conn *conn = (void *) arg;
1008
1009 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1010}
1011
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1013{
Marcel Holtmann01394182006-07-03 10:02:46 +02001014 struct l2cap_conn *conn = hcon->l2cap_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
Marcel Holtmann01394182006-07-03 10:02:46 +02001016 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 return conn;
1018
Marcel Holtmann01394182006-07-03 10:02:46 +02001019 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1020 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023 hcon->l2cap_data = conn;
1024 conn->hcon = hcon;
1025
Marcel Holtmann01394182006-07-03 10:02:46 +02001026 BT_DBG("hcon %p conn %p", hcon, conn);
1027
Ville Tervoacd7d372011-02-10 22:38:49 -03001028 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1029 conn->mtu = hcon->hdev->le_mtu;
1030 else
1031 conn->mtu = hcon->hdev->acl_mtu;
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 conn->src = &hcon->hdev->bdaddr;
1034 conn->dst = &hcon->dst;
1035
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001036 conn->feat_mask = 0;
1037
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001039 rwlock_init(&conn->chan_lock);
1040
1041 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001043 if (hcon->type == LE_LINK)
1044 setup_timer(&conn->security_timer, security_timeout,
1045 (unsigned long) conn);
1046 else
Ville Tervob62f3282011-02-10 22:38:50 -03001047 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +00001048 (unsigned long) conn);
1049
Marcel Holtmann2950f212009-02-12 14:02:50 +01001050 conn->disc_reason = 0x13;
1051
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 return conn;
1053}
1054
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001055static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001057 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001058 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001059 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060}
1061
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
1064/* Find socket with psm and source bdaddr.
1065 * Returns closest match.
1066 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001067static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001069 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001071 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001072
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001073 list_for_each_entry(c, &chan_list, global_l) {
1074 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001075
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001076 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 continue;
1078
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001079 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001081 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001082 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001083 return c;
1084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
1086 /* Closest match */
1087 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001088 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 }
1090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001092 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001093
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001094 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001097int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001099 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 bdaddr_t *src = &bt_sk(sk)->src;
1101 bdaddr_t *dst = &bt_sk(sk)->dst;
1102 struct l2cap_conn *conn;
1103 struct hci_conn *hcon;
1104 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001105 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001106 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001108 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001109 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001111 hdev = hci_get_route(dst, src);
1112 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 return -EHOSTUNREACH;
1114
1115 hci_dev_lock_bh(hdev);
1116
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001117 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001118
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001119 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001120 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001121 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001122 else
1123 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001124 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001125
Ville Tervo30e76272011-02-22 16:10:53 -03001126 if (IS_ERR(hcon)) {
1127 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001129 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130
1131 conn = l2cap_conn_add(hcon, 0);
1132 if (!conn) {
1133 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001134 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 goto done;
1136 }
1137
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 /* Update source addr of the socket */
1139 bacpy(src, conn->src);
1140
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001141 l2cap_chan_add(conn, chan);
1142
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001143 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001144 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
1146 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001147 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001148 __clear_chan_timer(chan);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001149 if (l2cap_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001150 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001151 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001152 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 }
1154
Ville Tervo30e76272011-02-22 16:10:53 -03001155 err = 0;
1156
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157done:
1158 hci_dev_unlock_bh(hdev);
1159 hci_dev_put(hdev);
1160 return err;
1161}
1162
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001163int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001164{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001165 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001166 DECLARE_WAITQUEUE(wait, current);
1167 int err = 0;
1168 int timeo = HZ/5;
1169
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001170 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001171 while ((chan->unacked_frames > 0 && chan->conn)) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001172 set_current_state(TASK_INTERRUPTIBLE);
1173
1174 if (!timeo)
1175 timeo = HZ/5;
1176
1177 if (signal_pending(current)) {
1178 err = sock_intr_errno(timeo);
1179 break;
1180 }
1181
1182 release_sock(sk);
1183 timeo = schedule_timeout(timeo);
1184 lock_sock(sk);
1185
1186 err = sock_error(sk);
1187 if (err)
1188 break;
1189 }
1190 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001191 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001192 return err;
1193}
1194
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001195static void l2cap_monitor_timeout(unsigned long arg)
1196{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001197 struct l2cap_chan *chan = (void *) arg;
1198 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001199
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001200 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001201
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001202 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001203 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001204 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001205 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001206 return;
1207 }
1208
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001209 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001210 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001211
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001212 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001213 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001214}
1215
1216static void l2cap_retrans_timeout(unsigned long arg)
1217{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001218 struct l2cap_chan *chan = (void *) arg;
1219 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001220
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001221 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001222
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001223 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001224 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001225 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001226
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001227 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001228
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001229 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001230 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001231}
1232
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001233static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001234{
1235 struct sk_buff *skb;
1236
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001237 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001238 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001239 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001240 break;
1241
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001242 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001243 kfree_skb(skb);
1244
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001245 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001246 }
1247
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001248 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001249 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001250}
1251
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001252void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001253{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001254 struct hci_conn *hcon = chan->conn->hcon;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001255 u16 flags;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001256
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001257 BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001258
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001259 if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001260 flags = ACL_START_NO_FLUSH;
1261 else
1262 flags = ACL_START;
1263
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -07001264 bt_cb(skb)->force_active = chan->force_active;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001265 hci_send_acl(hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001266}
1267
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001268void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001269{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001270 struct sk_buff *skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001271 u16 control, fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001272
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001273 while ((skb = skb_dequeue(&chan->tx_q))) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001274 control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001275 control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001276 put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001277
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001278 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001279 fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
1280 put_unaligned_le16(fcs, skb->data + skb->len - 2);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001281 }
1282
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001283 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001284
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001285 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001286 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001287}
1288
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001289static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001290{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001291 struct sk_buff *skb, *tx_skb;
1292 u16 control, fcs;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001293
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001294 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001295 if (!skb)
1296 return;
1297
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001298 do {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001299 if (bt_cb(skb)->tx_seq == tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001300 break;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001301
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001302 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001303 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001304
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001305 } while ((skb = skb_queue_next(&chan->tx_q, skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001306
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001307 if (chan->remote_max_tx &&
1308 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001309 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001310 return;
1311 }
1312
1313 tx_skb = skb_clone(skb, GFP_ATOMIC);
1314 bt_cb(skb)->retries++;
1315 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Ruiyi Zhanga429b512011-04-18 11:04:30 +08001316 control &= L2CAP_CTRL_SAR;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001317
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001318 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001319 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001320 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001321 }
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001322
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001323 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001324 | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001325
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001326 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1327
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001328 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001329 fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
1330 put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
1331 }
1332
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001333 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001334}
1335
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001336int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001337{
1338 struct sk_buff *skb, *tx_skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001339 u16 control, fcs;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001340 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001341
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001342 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001343 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001344
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001345 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001346
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001347 if (chan->remote_max_tx &&
1348 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001349 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001350 break;
1351 }
1352
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001353 tx_skb = skb_clone(skb, GFP_ATOMIC);
1354
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001355 bt_cb(skb)->retries++;
1356
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001357 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001358 control &= L2CAP_CTRL_SAR;
1359
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001360 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001361 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001362 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001363 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001364 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
1365 | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001366 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1367
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001368
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001369 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001370 fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
1371 put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
1372 }
1373
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001374 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001375
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001376 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001377
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001378 bt_cb(skb)->tx_seq = chan->next_tx_seq;
1379 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001380
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301381 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001382 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301383
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001384 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001385
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001386 if (skb_queue_is_last(&chan->tx_q, skb))
1387 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001388 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001389 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001390
1391 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001392 }
1393
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001394 return nsent;
1395}
1396
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001397static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001398{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001399 int ret;
1400
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001401 if (!skb_queue_empty(&chan->tx_q))
1402 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001403
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001404 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001405 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001406 return ret;
1407}
1408
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001409static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001410{
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001411 u16 control = 0;
1412
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001413 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001414
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001415 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001416 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001417 chan->conn_state |= L2CAP_CONN_RNR_SENT;
1418 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001419 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001420 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001421
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001422 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001423 return;
1424
1425 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001426 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001427}
1428
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001429static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001430{
1431 struct srej_list *tail;
1432 u16 control;
1433
1434 control = L2CAP_SUPER_SELECT_REJECT;
1435 control |= L2CAP_CTRL_FINAL;
1436
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001437 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001438 control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
1439
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001440 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001441}
1442
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001443static 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 -07001444{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001445 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001446 struct sk_buff **frag;
1447 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001449 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001450 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451
1452 sent += count;
1453 len -= count;
1454
1455 /* Continuation fragments (no L2CAP header) */
1456 frag = &skb_shinfo(skb)->frag_list;
1457 while (len) {
1458 count = min_t(unsigned int, conn->mtu, len);
1459
1460 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1461 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001462 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001463 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1464 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465
1466 sent += count;
1467 len -= count;
1468
1469 frag = &(*frag)->next;
1470 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
1472 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001473}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001475struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001476{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001477 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001478 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001479 struct sk_buff *skb;
1480 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1481 struct l2cap_hdr *lh;
1482
1483 BT_DBG("sk %p len %d", sk, (int)len);
1484
1485 count = min_t(unsigned int, (conn->mtu - hlen), len);
1486 skb = bt_skb_send_alloc(sk, count + hlen,
1487 msg->msg_flags & MSG_DONTWAIT, &err);
1488 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001489 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001490
1491 /* Create L2CAP header */
1492 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001493 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001494 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001495 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001496
1497 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1498 if (unlikely(err < 0)) {
1499 kfree_skb(skb);
1500 return ERR_PTR(err);
1501 }
1502 return skb;
1503}
1504
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001505struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001506{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001507 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001508 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001509 struct sk_buff *skb;
1510 int err, count, hlen = L2CAP_HDR_SIZE;
1511 struct l2cap_hdr *lh;
1512
1513 BT_DBG("sk %p len %d", sk, (int)len);
1514
1515 count = min_t(unsigned int, (conn->mtu - hlen), len);
1516 skb = bt_skb_send_alloc(sk, count + hlen,
1517 msg->msg_flags & MSG_DONTWAIT, &err);
1518 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001519 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001520
1521 /* Create L2CAP header */
1522 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001523 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001524 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1525
1526 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1527 if (unlikely(err < 0)) {
1528 kfree_skb(skb);
1529 return ERR_PTR(err);
1530 }
1531 return skb;
1532}
1533
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001534struct 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 -03001535{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001536 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001537 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001538 struct sk_buff *skb;
1539 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1540 struct l2cap_hdr *lh;
1541
1542 BT_DBG("sk %p len %d", sk, (int)len);
1543
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001544 if (!conn)
1545 return ERR_PTR(-ENOTCONN);
1546
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001547 if (sdulen)
1548 hlen += 2;
1549
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001550 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001551 hlen += 2;
1552
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001553 count = min_t(unsigned int, (conn->mtu - hlen), len);
1554 skb = bt_skb_send_alloc(sk, count + hlen,
1555 msg->msg_flags & MSG_DONTWAIT, &err);
1556 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001557 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001558
1559 /* Create L2CAP header */
1560 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001561 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001562 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1563 put_unaligned_le16(control, skb_put(skb, 2));
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001564 if (sdulen)
1565 put_unaligned_le16(sdulen, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001566
1567 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1568 if (unlikely(err < 0)) {
1569 kfree_skb(skb);
1570 return ERR_PTR(err);
1571 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001572
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001573 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001574 put_unaligned_le16(0, skb_put(skb, 2));
1575
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001576 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001577 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578}
1579
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001580int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001581{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001582 struct sk_buff *skb;
1583 struct sk_buff_head sar_queue;
1584 u16 control;
1585 size_t size = 0;
1586
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001587 skb_queue_head_init(&sar_queue);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001588 control = L2CAP_SDU_START;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001589 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001590 if (IS_ERR(skb))
1591 return PTR_ERR(skb);
1592
1593 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001594 len -= chan->remote_mps;
1595 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001596
1597 while (len > 0) {
1598 size_t buflen;
1599
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001600 if (len > chan->remote_mps) {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001601 control = L2CAP_SDU_CONTINUE;
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001602 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001603 } else {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001604 control = L2CAP_SDU_END;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001605 buflen = len;
1606 }
1607
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001608 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001609 if (IS_ERR(skb)) {
1610 skb_queue_purge(&sar_queue);
1611 return PTR_ERR(skb);
1612 }
1613
1614 __skb_queue_tail(&sar_queue, skb);
1615 len -= buflen;
1616 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001617 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001618 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1619 if (chan->tx_send_head == NULL)
1620 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001621
1622 return size;
1623}
1624
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001625int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
1626{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001627 struct sk_buff *skb;
1628 u16 control;
1629 int err;
1630
1631 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001632 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001633 skb = l2cap_create_connless_pdu(chan, msg, len);
1634 if (IS_ERR(skb))
1635 return PTR_ERR(skb);
1636
1637 l2cap_do_send(chan, skb);
1638 return len;
1639 }
1640
1641 switch (chan->mode) {
1642 case L2CAP_MODE_BASIC:
1643 /* Check outgoing MTU */
1644 if (len > chan->omtu)
1645 return -EMSGSIZE;
1646
1647 /* Create a basic PDU */
1648 skb = l2cap_create_basic_pdu(chan, msg, len);
1649 if (IS_ERR(skb))
1650 return PTR_ERR(skb);
1651
1652 l2cap_do_send(chan, skb);
1653 err = len;
1654 break;
1655
1656 case L2CAP_MODE_ERTM:
1657 case L2CAP_MODE_STREAMING:
1658 /* Entire SDU fits into one PDU */
1659 if (len <= chan->remote_mps) {
1660 control = L2CAP_SDU_UNSEGMENTED;
1661 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1662 0);
1663 if (IS_ERR(skb))
1664 return PTR_ERR(skb);
1665
1666 __skb_queue_tail(&chan->tx_q, skb);
1667
1668 if (chan->tx_send_head == NULL)
1669 chan->tx_send_head = skb;
1670
1671 } else {
1672 /* Segment SDU into multiples PDUs */
1673 err = l2cap_sar_segment_sdu(chan, msg, len);
1674 if (err < 0)
1675 return err;
1676 }
1677
1678 if (chan->mode == L2CAP_MODE_STREAMING) {
1679 l2cap_streaming_send(chan);
1680 err = len;
1681 break;
1682 }
1683
1684 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
1685 (chan->conn_state & L2CAP_CONN_WAIT_F)) {
1686 err = len;
1687 break;
1688 }
1689
1690 err = l2cap_ertm_send(chan);
1691 if (err >= 0)
1692 err = len;
1693
1694 break;
1695
1696 default:
1697 BT_DBG("bad state %1.1x", chan->mode);
1698 err = -EBADFD;
1699 }
1700
1701 return err;
1702}
1703
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704/* Copy frame to all raw sockets on that connection */
1705static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1706{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001708 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709
1710 BT_DBG("conn %p", conn);
1711
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001712 read_lock(&conn->chan_lock);
1713 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001714 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001715 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 continue;
1717
1718 /* Don't send frame to the socket it came from */
1719 if (skb->sk == sk)
1720 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001721 nskb = skb_clone(skb, GFP_ATOMIC);
1722 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 continue;
1724
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001725 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 kfree_skb(nskb);
1727 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001728 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729}
1730
1731/* ---- L2CAP signalling commands ---- */
1732static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1733 u8 code, u8 ident, u16 dlen, void *data)
1734{
1735 struct sk_buff *skb, **frag;
1736 struct l2cap_cmd_hdr *cmd;
1737 struct l2cap_hdr *lh;
1738 int len, count;
1739
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001740 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1741 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742
1743 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1744 count = min_t(unsigned int, conn->mtu, len);
1745
1746 skb = bt_skb_alloc(count, GFP_ATOMIC);
1747 if (!skb)
1748 return NULL;
1749
1750 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001751 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001752
1753 if (conn->hcon->type == LE_LINK)
1754 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1755 else
1756 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
1758 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1759 cmd->code = code;
1760 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001761 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762
1763 if (dlen) {
1764 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1765 memcpy(skb_put(skb, count), data, count);
1766 data += count;
1767 }
1768
1769 len -= skb->len;
1770
1771 /* Continuation fragments (no L2CAP header) */
1772 frag = &skb_shinfo(skb)->frag_list;
1773 while (len) {
1774 count = min_t(unsigned int, conn->mtu, len);
1775
1776 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1777 if (!*frag)
1778 goto fail;
1779
1780 memcpy(skb_put(*frag, count), data, count);
1781
1782 len -= count;
1783 data += count;
1784
1785 frag = &(*frag)->next;
1786 }
1787
1788 return skb;
1789
1790fail:
1791 kfree_skb(skb);
1792 return NULL;
1793}
1794
1795static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1796{
1797 struct l2cap_conf_opt *opt = *ptr;
1798 int len;
1799
1800 len = L2CAP_CONF_OPT_SIZE + opt->len;
1801 *ptr += len;
1802
1803 *type = opt->type;
1804 *olen = opt->len;
1805
1806 switch (opt->len) {
1807 case 1:
1808 *val = *((u8 *) opt->val);
1809 break;
1810
1811 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001812 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001813 break;
1814
1815 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001816 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817 break;
1818
1819 default:
1820 *val = (unsigned long) opt->val;
1821 break;
1822 }
1823
1824 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1825 return len;
1826}
1827
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1829{
1830 struct l2cap_conf_opt *opt = *ptr;
1831
1832 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1833
1834 opt->type = type;
1835 opt->len = len;
1836
1837 switch (len) {
1838 case 1:
1839 *((u8 *) opt->val) = val;
1840 break;
1841
1842 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001843 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 break;
1845
1846 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001847 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 break;
1849
1850 default:
1851 memcpy(opt->val, (void *) val, len);
1852 break;
1853 }
1854
1855 *ptr += L2CAP_CONF_OPT_SIZE + len;
1856}
1857
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001858static void l2cap_ack_timeout(unsigned long arg)
1859{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001860 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001861
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001862 bh_lock_sock(chan->sk);
1863 l2cap_send_ack(chan);
1864 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001865}
1866
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001867static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001868{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001869 struct sock *sk = chan->sk;
1870
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001871 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001872 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001873 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001874 chan->num_acked = 0;
1875 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001876
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001877 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1878 (unsigned long) chan);
1879 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1880 (unsigned long) chan);
1881 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001882
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001883 skb_queue_head_init(&chan->srej_q);
1884 skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001885
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001886 INIT_LIST_HEAD(&chan->srej_l);
1887
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03001888 INIT_WORK(&chan->busy_work, l2cap_busy_work);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001889
1890 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001891}
1892
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001893static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1894{
1895 switch (mode) {
1896 case L2CAP_MODE_STREAMING:
1897 case L2CAP_MODE_ERTM:
1898 if (l2cap_mode_supported(mode, remote_feat_mask))
1899 return mode;
1900 /* fall through */
1901 default:
1902 return L2CAP_MODE_BASIC;
1903 }
1904}
1905
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03001906static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001909 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 void *ptr = req->data;
1911
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001912 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001914 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001915 goto done;
1916
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001917 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001918 case L2CAP_MODE_STREAMING:
1919 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001920 if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001921 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001922
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03001923 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001924 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001925 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001926 break;
1927 }
1928
1929done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001930 if (chan->imtu != L2CAP_DEFAULT_MTU)
1931 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02001932
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001933 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001934 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001935 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
1936 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001937 break;
1938
Gustavo F. Padovan62547752010-06-08 20:05:31 -03001939 rfc.mode = L2CAP_MODE_BASIC;
1940 rfc.txwin_size = 0;
1941 rfc.max_transmit = 0;
1942 rfc.retrans_timeout = 0;
1943 rfc.monitor_timeout = 0;
1944 rfc.max_pdu_size = 0;
1945
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001946 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1947 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001948 break;
1949
1950 case L2CAP_MODE_ERTM:
1951 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001952 rfc.txwin_size = chan->tx_win;
1953 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001954 rfc.retrans_timeout = 0;
1955 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001956 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001957 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1958 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001959
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001960 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1961 (unsigned long) &rfc);
1962
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001963 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001964 break;
1965
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001966 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001967 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001968 chan->fcs = L2CAP_FCS_NONE;
1969 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001970 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001971 break;
1972
1973 case L2CAP_MODE_STREAMING:
1974 rfc.mode = L2CAP_MODE_STREAMING;
1975 rfc.txwin_size = 0;
1976 rfc.max_transmit = 0;
1977 rfc.retrans_timeout = 0;
1978 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001979 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001980 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1981 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001982
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001983 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1984 (unsigned long) &rfc);
1985
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001986 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001987 break;
1988
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001989 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001990 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001991 chan->fcs = L2CAP_FCS_NONE;
1992 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001993 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001994 break;
1995 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001997 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001998 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999
2000 return ptr - data;
2001}
2002
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002003static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002005 struct l2cap_conf_rsp *rsp = data;
2006 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002007 void *req = chan->conf_req;
2008 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002009 int type, hint, olen;
2010 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002011 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Marcel Holtmann861d6882007-10-20 13:37:06 +02002012 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002013 u16 result = L2CAP_CONF_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002015 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002016
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002017 while (len >= L2CAP_CONF_OPT_SIZE) {
2018 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002019
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002020 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002021 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002022
2023 switch (type) {
2024 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002025 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002026 break;
2027
2028 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002029 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002030 break;
2031
2032 case L2CAP_CONF_QOS:
2033 break;
2034
Marcel Holtmann6464f352007-10-20 13:39:51 +02002035 case L2CAP_CONF_RFC:
2036 if (olen == sizeof(rfc))
2037 memcpy(&rfc, (void *) val, olen);
2038 break;
2039
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002040 case L2CAP_CONF_FCS:
2041 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002042 chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002043
2044 break;
2045
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002046 default:
2047 if (hint)
2048 break;
2049
2050 result = L2CAP_CONF_UNKNOWN;
2051 *((u8 *) ptr++) = type;
2052 break;
2053 }
2054 }
2055
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002056 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002057 goto done;
2058
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002059 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002060 case L2CAP_MODE_STREAMING:
2061 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002062 if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002063 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002064 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002065 break;
2066 }
2067
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002068 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002069 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002070
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002071 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002072 }
2073
2074done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002075 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002076 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002077 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002078
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002079 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002080 return -ECONNREFUSED;
2081
2082 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2083 sizeof(rfc), (unsigned long) &rfc);
2084 }
2085
2086
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002087 if (result == L2CAP_CONF_SUCCESS) {
2088 /* Configure output options and let the other side know
2089 * which ones we don't like. */
2090
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002091 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2092 result = L2CAP_CONF_UNACCEPT;
2093 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002094 chan->omtu = mtu;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002095 chan->conf_state |= L2CAP_CONF_MTU_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002096 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002097 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002098
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002099 switch (rfc.mode) {
2100 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002101 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002102 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002103 break;
2104
2105 case L2CAP_MODE_ERTM:
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002106 chan->remote_tx_win = rfc.txwin_size;
2107 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002108
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002109 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2110 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002111
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002112 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002113
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002114 rfc.retrans_timeout =
2115 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2116 rfc.monitor_timeout =
2117 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002118
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002119 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002120
2121 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2122 sizeof(rfc), (unsigned long) &rfc);
2123
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002124 break;
2125
2126 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002127 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2128 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002129
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002130 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002131
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002132 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002133
2134 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2135 sizeof(rfc), (unsigned long) &rfc);
2136
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002137 break;
2138
2139 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002140 result = L2CAP_CONF_UNACCEPT;
2141
2142 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002143 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002144 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002145
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002146 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002147 chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002148 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002149 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002150 rsp->result = cpu_to_le16(result);
2151 rsp->flags = cpu_to_le16(0x0000);
2152
2153 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002154}
2155
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002156static 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 -03002157{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002158 struct l2cap_conf_req *req = data;
2159 void *ptr = req->data;
2160 int type, olen;
2161 unsigned long val;
2162 struct l2cap_conf_rfc rfc;
2163
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002164 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002165
2166 while (len >= L2CAP_CONF_OPT_SIZE) {
2167 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2168
2169 switch (type) {
2170 case L2CAP_CONF_MTU:
2171 if (val < L2CAP_DEFAULT_MIN_MTU) {
2172 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002173 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002174 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002175 chan->imtu = val;
2176 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002177 break;
2178
2179 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002180 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002181 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002182 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002183 break;
2184
2185 case L2CAP_CONF_RFC:
2186 if (olen == sizeof(rfc))
2187 memcpy(&rfc, (void *)val, olen);
2188
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002189 if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002190 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002191 return -ECONNREFUSED;
2192
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002193 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002194
2195 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2196 sizeof(rfc), (unsigned long) &rfc);
2197 break;
2198 }
2199 }
2200
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002201 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002202 return -ECONNREFUSED;
2203
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002204 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002205
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002206 if (*result == L2CAP_CONF_SUCCESS) {
2207 switch (rfc.mode) {
2208 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002209 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2210 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2211 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002212 break;
2213 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002214 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002215 }
2216 }
2217
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002218 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002219 req->flags = cpu_to_le16(0x0000);
2220
2221 return ptr - data;
2222}
2223
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002224static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225{
2226 struct l2cap_conf_rsp *rsp = data;
2227 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002229 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002231 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002232 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002233 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234
2235 return ptr - data;
2236}
2237
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002238void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002239{
2240 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002241 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002242 u8 buf[128];
2243
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002244 rsp.scid = cpu_to_le16(chan->dcid);
2245 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002246 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2247 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2248 l2cap_send_cmd(conn, chan->ident,
2249 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2250
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002251 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002252 return;
2253
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002254 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002255 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2256 l2cap_build_conf_req(chan, buf), buf);
2257 chan->num_conf_req++;
2258}
2259
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002260static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002261{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002262 int type, olen;
2263 unsigned long val;
2264 struct l2cap_conf_rfc rfc;
2265
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002266 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002267
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002268 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002269 return;
2270
2271 while (len >= L2CAP_CONF_OPT_SIZE) {
2272 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2273
2274 switch (type) {
2275 case L2CAP_CONF_RFC:
2276 if (olen == sizeof(rfc))
2277 memcpy(&rfc, (void *)val, olen);
2278 goto done;
2279 }
2280 }
2281
2282done:
2283 switch (rfc.mode) {
2284 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002285 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2286 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2287 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002288 break;
2289 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002290 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002291 }
2292}
2293
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002294static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2295{
2296 struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
2297
2298 if (rej->reason != 0x0000)
2299 return 0;
2300
2301 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2302 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002303 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002304
2305 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002306 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002307
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002308 l2cap_conn_start(conn);
2309 }
2310
2311 return 0;
2312}
2313
Linus Torvalds1da177e2005-04-16 15:20:36 -07002314static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2315{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2317 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002318 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002319 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002320 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321
2322 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002323 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324
2325 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2326
2327 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002328 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2329 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002330 result = L2CAP_CR_BAD_PSM;
2331 goto sendresp;
2332 }
2333
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002334 parent = pchan->sk;
2335
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002336 bh_lock_sock(parent);
2337
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002338 /* Check if the ACL is secure enough (if not SDP) */
2339 if (psm != cpu_to_le16(0x0001) &&
2340 !hci_conn_check_link_mode(conn->hcon)) {
Marcel Holtmann2950f212009-02-12 14:02:50 +01002341 conn->disc_reason = 0x05;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002342 result = L2CAP_CR_SEC_BLOCK;
2343 goto response;
2344 }
2345
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 result = L2CAP_CR_NO_MEM;
2347
2348 /* Check for backlog size */
2349 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002350 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 goto response;
2352 }
2353
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002354 chan = pchan->ops->new_connection(pchan->data);
2355 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 goto response;
2357
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002358 sk = chan->sk;
2359
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002360 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361
2362 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002363 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2364 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002366 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367 goto response;
2368 }
2369
2370 hci_conn_hold(conn->hcon);
2371
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 bacpy(&bt_sk(sk)->src, conn->src);
2373 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002374 chan->psm = psm;
2375 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002377 bt_accept_enqueue(parent, sk);
2378
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002379 __l2cap_chan_add(conn, chan);
2380
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002381 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002383 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002385 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
Marcel Holtmann984947d2009-02-06 23:35:19 +01002387 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03002388 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002389 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002390 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002391 result = L2CAP_CR_PEND;
2392 status = L2CAP_CS_AUTHOR_PEND;
2393 parent->sk_data_ready(parent, 0);
2394 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002395 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002396 result = L2CAP_CR_SUCCESS;
2397 status = L2CAP_CS_NO_INFO;
2398 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002399 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002400 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002401 result = L2CAP_CR_PEND;
2402 status = L2CAP_CS_AUTHEN_PEND;
2403 }
2404 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002405 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002406 result = L2CAP_CR_PEND;
2407 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 }
2409
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002410 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
2412response:
2413 bh_unlock_sock(parent);
2414
2415sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002416 rsp.scid = cpu_to_le16(scid);
2417 rsp.dcid = cpu_to_le16(dcid);
2418 rsp.result = cpu_to_le16(result);
2419 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002421
2422 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2423 struct l2cap_info_req info;
2424 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2425
2426 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2427 conn->info_ident = l2cap_get_ident(conn);
2428
2429 mod_timer(&conn->info_timer, jiffies +
2430 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2431
2432 l2cap_send_cmd(conn, conn->info_ident,
2433 L2CAP_INFO_REQ, sizeof(info), &info);
2434 }
2435
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002436 if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002437 result == L2CAP_CR_SUCCESS) {
2438 u8 buf[128];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002439 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002440 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002441 l2cap_build_conf_req(chan, buf), buf);
2442 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002443 }
2444
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 return 0;
2446}
2447
2448static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2449{
2450 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2451 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002452 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 struct sock *sk;
2454 u8 req[128];
2455
2456 scid = __le16_to_cpu(rsp->scid);
2457 dcid = __le16_to_cpu(rsp->dcid);
2458 result = __le16_to_cpu(rsp->result);
2459 status = __le16_to_cpu(rsp->status);
2460
2461 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2462
2463 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002464 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002465 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002466 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002468 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002469 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002470 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 }
2472
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002473 sk = chan->sk;
2474
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 switch (result) {
2476 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002477 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002478 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002479 chan->dcid = dcid;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002480 chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002481
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002482 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002483 break;
2484
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002485 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002486
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002488 l2cap_build_conf_req(chan, req), req);
2489 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002490 break;
2491
2492 case L2CAP_CR_PEND:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002493 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 break;
2495
2496 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002497 /* don't delete l2cap channel if sk is owned by user */
2498 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002499 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002500 __clear_chan_timer(chan);
2501 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002502 break;
2503 }
2504
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002505 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002506 break;
2507 }
2508
2509 bh_unlock_sock(sk);
2510 return 0;
2511}
2512
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002513static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002514{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002515 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
2516
Mat Martineau8c462b62010-08-24 15:35:42 -07002517 /* FCS is enabled only in ERTM or streaming mode, if one or both
2518 * sides request it.
2519 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002520 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002521 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002522 else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002523 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002524}
2525
Al Viro88219a02007-07-29 00:17:25 -07002526static 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 -07002527{
2528 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2529 u16 dcid, flags;
2530 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002531 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002533 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534
2535 dcid = __le16_to_cpu(req->dcid);
2536 flags = __le16_to_cpu(req->flags);
2537
2538 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2539
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002540 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002541 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 return -ENOENT;
2543
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002544 sk = chan->sk;
2545
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002546 if (chan->state != BT_CONFIG) {
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002547 struct l2cap_cmd_rej rej;
2548
2549 rej.reason = cpu_to_le16(0x0002);
2550 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2551 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002552 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002553 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002554
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002555 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002556 len = cmd_len - sizeof(*req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002557 if (chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002558 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002559 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002560 L2CAP_CONF_REJECT, flags), rsp);
2561 goto unlock;
2562 }
2563
2564 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002565 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2566 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567
2568 if (flags & 0x0001) {
2569 /* Incomplete config. Send empty response. */
2570 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002571 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002572 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573 goto unlock;
2574 }
2575
2576 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002577 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002578 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002579 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002583 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002584 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002585
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002586 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002587 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002588
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002589 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002590 goto unlock;
2591
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002592 if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002593 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002594
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002595 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002596
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002597 chan->next_tx_seq = 0;
2598 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002599 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002600 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002601 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002602
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002604 goto unlock;
2605 }
2606
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002607 if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002608 u8 buf[64];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002609 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002611 l2cap_build_conf_req(chan, buf), buf);
2612 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 }
2614
2615unlock:
2616 bh_unlock_sock(sk);
2617 return 0;
2618}
2619
2620static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2621{
2622 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2623 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002624 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002626 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
2628 scid = __le16_to_cpu(rsp->scid);
2629 flags = __le16_to_cpu(rsp->flags);
2630 result = __le16_to_cpu(rsp->result);
2631
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002632 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2633 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002635 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002636 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 return 0;
2638
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002639 sk = chan->sk;
2640
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 switch (result) {
2642 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002643 l2cap_conf_rfc_get(chan, rsp->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 break;
2645
2646 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002647 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002648 char req[64];
2649
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002650 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002651 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002652 goto done;
2653 }
2654
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002655 /* throw out any old stored conf requests */
2656 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002657 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2658 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002659 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002660 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002661 goto done;
2662 }
2663
2664 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2665 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002666 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002667 if (result != L2CAP_CONF_SUCCESS)
2668 goto done;
2669 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 }
2671
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002672 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002673 sk->sk_err = ECONNRESET;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002674 __set_chan_timer(chan, HZ * 5);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002675 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 goto done;
2677 }
2678
2679 if (flags & 0x01)
2680 goto done;
2681
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002682 chan->conf_state |= L2CAP_CONF_INPUT_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002684 if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002685 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002686
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002687 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002688 chan->next_tx_seq = 0;
2689 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002690 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002691 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002692 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002693
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 l2cap_chan_ready(sk);
2695 }
2696
2697done:
2698 bh_unlock_sock(sk);
2699 return 0;
2700}
2701
2702static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2703{
2704 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2705 struct l2cap_disconn_rsp rsp;
2706 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002707 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 struct sock *sk;
2709
2710 scid = __le16_to_cpu(req->scid);
2711 dcid = __le16_to_cpu(req->dcid);
2712
2713 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2714
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002715 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002716 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 return 0;
2718
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002719 sk = chan->sk;
2720
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002721 rsp.dcid = cpu_to_le16(chan->scid);
2722 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2724
2725 sk->sk_shutdown = SHUTDOWN_MASK;
2726
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002727 /* don't delete l2cap channel if sk is owned by user */
2728 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002729 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002730 __clear_chan_timer(chan);
2731 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002732 bh_unlock_sock(sk);
2733 return 0;
2734 }
2735
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002736 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 bh_unlock_sock(sk);
2738
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002739 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 return 0;
2741}
2742
2743static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2744{
2745 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
2746 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002747 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 struct sock *sk;
2749
2750 scid = __le16_to_cpu(rsp->scid);
2751 dcid = __le16_to_cpu(rsp->dcid);
2752
2753 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
2754
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002755 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002756 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 return 0;
2758
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002759 sk = chan->sk;
2760
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002761 /* don't delete l2cap channel if sk is owned by user */
2762 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002763 l2cap_state_change(chan,BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002764 __clear_chan_timer(chan);
2765 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002766 bh_unlock_sock(sk);
2767 return 0;
2768 }
2769
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002770 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 bh_unlock_sock(sk);
2772
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002773 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return 0;
2775}
2776
2777static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2778{
2779 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 u16 type;
2781
2782 type = __le16_to_cpu(req->type);
2783
2784 BT_DBG("type 0x%4.4x", type);
2785
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002786 if (type == L2CAP_IT_FEAT_MASK) {
2787 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07002788 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002789 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2790 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2791 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03002792 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002793 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
2794 | L2CAP_FEAT_FCS;
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03002795 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002796 l2cap_send_cmd(conn, cmd->ident,
2797 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002798 } else if (type == L2CAP_IT_FIXED_CHAN) {
2799 u8 buf[12];
2800 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2801 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2802 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
2803 memcpy(buf + 4, l2cap_fixed_chan, 8);
2804 l2cap_send_cmd(conn, cmd->ident,
2805 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002806 } else {
2807 struct l2cap_info_rsp rsp;
2808 rsp.type = cpu_to_le16(type);
2809 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
2810 l2cap_send_cmd(conn, cmd->ident,
2811 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
2812 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813
2814 return 0;
2815}
2816
2817static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2818{
2819 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
2820 u16 type, result;
2821
2822 type = __le16_to_cpu(rsp->type);
2823 result = __le16_to_cpu(rsp->result);
2824
2825 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
2826
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02002827 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
2828 if (cmd->ident != conn->info_ident ||
2829 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
2830 return 0;
2831
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002832 del_timer(&conn->info_timer);
2833
Ville Tervoadb08ed2010-08-04 09:43:33 +03002834 if (result != L2CAP_IR_SUCCESS) {
2835 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2836 conn->info_ident = 0;
2837
2838 l2cap_conn_start(conn);
2839
2840 return 0;
2841 }
2842
Marcel Holtmann984947d2009-02-06 23:35:19 +01002843 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07002844 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002845
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002846 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002847 struct l2cap_info_req req;
2848 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2849
2850 conn->info_ident = l2cap_get_ident(conn);
2851
2852 l2cap_send_cmd(conn, conn->info_ident,
2853 L2CAP_INFO_REQ, sizeof(req), &req);
2854 } else {
2855 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2856 conn->info_ident = 0;
2857
2858 l2cap_conn_start(conn);
2859 }
2860 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01002861 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002862 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002863
2864 l2cap_conn_start(conn);
2865 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002866
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 return 0;
2868}
2869
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002870static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02002871 u16 to_multiplier)
2872{
2873 u16 max_latency;
2874
2875 if (min > max || min < 6 || max > 3200)
2876 return -EINVAL;
2877
2878 if (to_multiplier < 10 || to_multiplier > 3200)
2879 return -EINVAL;
2880
2881 if (max >= to_multiplier * 8)
2882 return -EINVAL;
2883
2884 max_latency = (to_multiplier * 8 / max) - 1;
2885 if (latency > 499 || latency > max_latency)
2886 return -EINVAL;
2887
2888 return 0;
2889}
2890
2891static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
2892 struct l2cap_cmd_hdr *cmd, u8 *data)
2893{
2894 struct hci_conn *hcon = conn->hcon;
2895 struct l2cap_conn_param_update_req *req;
2896 struct l2cap_conn_param_update_rsp rsp;
2897 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002898 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02002899
2900 if (!(hcon->link_mode & HCI_LM_MASTER))
2901 return -EINVAL;
2902
2903 cmd_len = __le16_to_cpu(cmd->len);
2904 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
2905 return -EPROTO;
2906
2907 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002908 min = __le16_to_cpu(req->min);
2909 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02002910 latency = __le16_to_cpu(req->latency);
2911 to_multiplier = __le16_to_cpu(req->to_multiplier);
2912
2913 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
2914 min, max, latency, to_multiplier);
2915
2916 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002917
2918 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
2919 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02002920 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
2921 else
2922 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
2923
2924 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
2925 sizeof(rsp), &rsp);
2926
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002927 if (!err)
2928 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
2929
Claudio Takahaside731152011-02-11 19:28:55 -02002930 return 0;
2931}
2932
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002933static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
2934 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
2935{
2936 int err = 0;
2937
2938 switch (cmd->code) {
2939 case L2CAP_COMMAND_REJ:
2940 l2cap_command_rej(conn, cmd, data);
2941 break;
2942
2943 case L2CAP_CONN_REQ:
2944 err = l2cap_connect_req(conn, cmd, data);
2945 break;
2946
2947 case L2CAP_CONN_RSP:
2948 err = l2cap_connect_rsp(conn, cmd, data);
2949 break;
2950
2951 case L2CAP_CONF_REQ:
2952 err = l2cap_config_req(conn, cmd, cmd_len, data);
2953 break;
2954
2955 case L2CAP_CONF_RSP:
2956 err = l2cap_config_rsp(conn, cmd, data);
2957 break;
2958
2959 case L2CAP_DISCONN_REQ:
2960 err = l2cap_disconnect_req(conn, cmd, data);
2961 break;
2962
2963 case L2CAP_DISCONN_RSP:
2964 err = l2cap_disconnect_rsp(conn, cmd, data);
2965 break;
2966
2967 case L2CAP_ECHO_REQ:
2968 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
2969 break;
2970
2971 case L2CAP_ECHO_RSP:
2972 break;
2973
2974 case L2CAP_INFO_REQ:
2975 err = l2cap_information_req(conn, cmd, data);
2976 break;
2977
2978 case L2CAP_INFO_RSP:
2979 err = l2cap_information_rsp(conn, cmd, data);
2980 break;
2981
2982 default:
2983 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
2984 err = -EINVAL;
2985 break;
2986 }
2987
2988 return err;
2989}
2990
2991static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
2992 struct l2cap_cmd_hdr *cmd, u8 *data)
2993{
2994 switch (cmd->code) {
2995 case L2CAP_COMMAND_REJ:
2996 return 0;
2997
2998 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02002999 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003000
3001 case L2CAP_CONN_PARAM_UPDATE_RSP:
3002 return 0;
3003
3004 default:
3005 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3006 return -EINVAL;
3007 }
3008}
3009
3010static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3011 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012{
3013 u8 *data = skb->data;
3014 int len = skb->len;
3015 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003016 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
3018 l2cap_raw_recv(conn, skb);
3019
3020 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003021 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3023 data += L2CAP_CMD_HDR_SIZE;
3024 len -= L2CAP_CMD_HDR_SIZE;
3025
Al Viro88219a02007-07-29 00:17:25 -07003026 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027
Al Viro88219a02007-07-29 00:17:25 -07003028 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 -07003029
Al Viro88219a02007-07-29 00:17:25 -07003030 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 BT_DBG("corrupted command");
3032 break;
3033 }
3034
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003035 if (conn->hcon->type == LE_LINK)
3036 err = l2cap_le_sig_cmd(conn, &cmd, data);
3037 else
3038 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039
3040 if (err) {
3041 struct l2cap_cmd_rej rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003042
3043 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044
3045 /* FIXME: Map err to a valid reason */
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07003046 rej.reason = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3048 }
3049
Al Viro88219a02007-07-29 00:17:25 -07003050 data += cmd_len;
3051 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 }
3053
3054 kfree_skb(skb);
3055}
3056
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003057static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003058{
3059 u16 our_fcs, rcv_fcs;
3060 int hdr_size = L2CAP_HDR_SIZE + 2;
3061
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003062 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003063 skb_trim(skb, skb->len - 2);
3064 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3065 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3066
3067 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003068 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003069 }
3070 return 0;
3071}
3072
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003073static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003074{
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003075 u16 control = 0;
3076
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003077 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003078
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003079 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003080
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003081 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan64988862010-05-10 14:54:14 -03003082 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003083 l2cap_send_sframe(chan, control);
3084 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003085 }
3086
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003087 if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
3088 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003089
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003090 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003091
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003092 if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003093 chan->frames_sent == 0) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003094 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003095 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003096 }
3097}
3098
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003099static 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 -03003100{
3101 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003102 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003103
3104 bt_cb(skb)->tx_seq = tx_seq;
3105 bt_cb(skb)->sar = sar;
3106
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003107 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003108 if (!next_skb) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003109 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003110 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003111 }
3112
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003113 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003114 if (tx_seq_offset < 0)
3115 tx_seq_offset += 64;
3116
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003117 do {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003118 if (bt_cb(next_skb)->tx_seq == tx_seq)
3119 return -EINVAL;
3120
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003121 next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003122 chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003123 if (next_tx_seq_offset < 0)
3124 next_tx_seq_offset += 64;
3125
3126 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003127 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003128 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003129 }
3130
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003131 if (skb_queue_is_last(&chan->srej_q, next_skb))
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003132 break;
3133
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003134 } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003135
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003136 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003137
3138 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003139}
3140
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003141static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003142{
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003143 struct sk_buff *_skb;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003144 int err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003145
3146 switch (control & L2CAP_CTRL_SAR) {
3147 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003148 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003149 goto drop;
3150
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003151 return chan->ops->recv(chan->data, skb);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003152
3153 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003154 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003155 goto drop;
3156
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003157 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003158
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003159 if (chan->sdu_len > chan->imtu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003160 goto disconnect;
3161
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003162 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3163 if (!chan->sdu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003164 return -ENOMEM;
3165
3166 /* pull sdu_len bytes only after alloc, because of Local Busy
3167 * condition we have to be sure that this will be executed
3168 * only once, i.e., when alloc does not fail */
3169 skb_pull(skb, 2);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003170
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003171 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003172
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003173 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003174 chan->partial_sdu_len = skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003175 break;
3176
3177 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003178 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003179 goto disconnect;
3180
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003181 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003182 goto disconnect;
3183
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003184 chan->partial_sdu_len += skb->len;
3185 if (chan->partial_sdu_len > chan->sdu_len)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003186 goto drop;
3187
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003188 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003189
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003190 break;
3191
3192 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003193 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003194 goto disconnect;
3195
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003196 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003197 goto disconnect;
3198
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003199 if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003200 chan->partial_sdu_len += skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003201
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003202 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003203 goto drop;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003204
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003205 if (chan->partial_sdu_len != chan->sdu_len)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003206 goto drop;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003207
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003208 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003209 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003210
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003211 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003212 if (!_skb) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003213 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003214 return -ENOMEM;
3215 }
3216
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003217 err = chan->ops->recv(chan->data, _skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003218 if (err < 0) {
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003219 kfree_skb(_skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003220 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003221 return err;
3222 }
3223
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003224 chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
3225 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003226
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003227 kfree_skb(chan->sdu);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003228 break;
3229 }
3230
3231 kfree_skb(skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003232 return 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003233
3234drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003235 kfree_skb(chan->sdu);
3236 chan->sdu = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003237
3238disconnect:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003239 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003240 kfree_skb(skb);
3241 return 0;
3242}
3243
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003244static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003245{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003246 struct sk_buff *skb;
3247 u16 control;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003248 int err;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003249
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003250 while ((skb = skb_dequeue(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003251 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003252 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003253 if (err < 0) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003254 skb_queue_head(&chan->busy_q, skb);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003255 return -EBUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003256 }
3257
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003258 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003259 }
3260
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003261 if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003262 goto done;
3263
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003264 control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003265 control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003266 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003267 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003268
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003269 __clear_retrans_timer(chan);
3270 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003271
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003272 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003273
3274done:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003275 chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
3276 chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003277
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003278 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003279
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003280 return 0;
3281}
3282
3283static void l2cap_busy_work(struct work_struct *work)
3284{
3285 DECLARE_WAITQUEUE(wait, current);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003286 struct l2cap_chan *chan =
3287 container_of(work, struct l2cap_chan, busy_work);
3288 struct sock *sk = chan->sk;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003289 int n_tries = 0, timeo = HZ/5, err;
3290 struct sk_buff *skb;
3291
3292 lock_sock(sk);
3293
3294 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003295 while ((skb = skb_peek(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003296 set_current_state(TASK_INTERRUPTIBLE);
3297
3298 if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
3299 err = -EBUSY;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003300 l2cap_send_disconn_req(chan->conn, chan, EBUSY);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003301 break;
3302 }
3303
3304 if (!timeo)
3305 timeo = HZ/5;
3306
3307 if (signal_pending(current)) {
3308 err = sock_intr_errno(timeo);
3309 break;
3310 }
3311
3312 release_sock(sk);
3313 timeo = schedule_timeout(timeo);
3314 lock_sock(sk);
3315
3316 err = sock_error(sk);
3317 if (err)
3318 break;
3319
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003320 if (l2cap_try_push_rx_skb(chan) == 0)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003321 break;
3322 }
3323
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003324 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02003325 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003326
3327 release_sock(sk);
3328}
3329
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003330static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003331{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003332 int sctrl, err;
3333
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003334 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003335 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003336 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003337 return l2cap_try_push_rx_skb(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003338
3339
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003340 }
3341
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003342 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003343 if (err >= 0) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003344 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003345 return err;
3346 }
3347
3348 /* Busy Condition */
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003349 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003350
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003351 chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003352 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003353 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003354
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003355 sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003356 sctrl |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003357 l2cap_send_sframe(chan, sctrl);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003358
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003359 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003360
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003361 __clear_ack_timer(chan);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003362
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003363 queue_work(_busy_wq, &chan->busy_work);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003364
3365 return err;
3366}
3367
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003368static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003369{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003370 struct sk_buff *_skb;
3371 int err = -EINVAL;
3372
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003373 /*
3374 * TODO: We have to notify the userland if some data is lost with the
3375 * Streaming Mode.
3376 */
3377
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003378 switch (control & L2CAP_CTRL_SAR) {
3379 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003380 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003381 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003382 break;
3383 }
3384
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003385 err = chan->ops->recv(chan->data, skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003386 if (!err)
3387 return 0;
3388
3389 break;
3390
3391 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003392 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003393 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003394 break;
3395 }
3396
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003397 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003398 skb_pull(skb, 2);
3399
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003400 if (chan->sdu_len > chan->imtu) {
Gustavo F. Padovan052897c2010-05-01 16:15:40 -03003401 err = -EMSGSIZE;
3402 break;
3403 }
3404
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003405 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3406 if (!chan->sdu) {
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003407 err = -ENOMEM;
3408 break;
3409 }
3410
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003411 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003412
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003413 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003414 chan->partial_sdu_len = skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003415 err = 0;
3416 break;
3417
3418 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003419 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003420 break;
3421
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003422 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003423
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003424 chan->partial_sdu_len += skb->len;
3425 if (chan->partial_sdu_len > chan->sdu_len)
3426 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003427 else
3428 err = 0;
3429
3430 break;
3431
3432 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003433 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003434 break;
3435
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003436 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003437
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003438 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003439 chan->partial_sdu_len += skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003440
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003441 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003442 goto drop;
3443
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003444 if (chan->partial_sdu_len == chan->sdu_len) {
3445 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003446 err = chan->ops->recv(chan->data, _skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003447 if (err < 0)
3448 kfree_skb(_skb);
3449 }
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003450 err = 0;
3451
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003452drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003453 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003454 break;
3455 }
3456
3457 kfree_skb(skb);
3458 return err;
3459}
3460
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003461static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003462{
3463 struct sk_buff *skb;
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003464 u16 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003465
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003466 while ((skb = skb_peek(&chan->srej_q))) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003467 if (bt_cb(skb)->tx_seq != tx_seq)
3468 break;
3469
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003470 skb = skb_dequeue(&chan->srej_q);
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003471 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003472 l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003473 chan->buffer_seq_srej =
3474 (chan->buffer_seq_srej + 1) % 64;
Gustavo F. Padovan8ff50ec2010-05-10 19:34:11 -03003475 tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003476 }
3477}
3478
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003479static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003480{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003481 struct srej_list *l, *tmp;
3482 u16 control;
3483
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003484 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003485 if (l->tx_seq == tx_seq) {
3486 list_del(&l->list);
3487 kfree(l);
3488 return;
3489 }
3490 control = L2CAP_SUPER_SELECT_REJECT;
3491 control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003492 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003493 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003494 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003495 }
3496}
3497
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003498static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003499{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003500 struct srej_list *new;
3501 u16 control;
3502
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003503 while (tx_seq != chan->expected_tx_seq) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003504 control = L2CAP_SUPER_SELECT_REJECT;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003505 control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003506 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003507
3508 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003509 new->tx_seq = chan->expected_tx_seq;
3510 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003511 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003512 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003513 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003514}
3515
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003516static 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 -03003517{
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003518 u8 tx_seq = __get_txseq(rx_control);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003519 u8 req_seq = __get_reqseq(rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003520 u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003521 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003522 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003523 int err = 0;
3524
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003525 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
3526 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003527
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003528 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003529 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003530 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003531 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003532 __set_retrans_timer(chan);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003533 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003534 }
3535
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003536 chan->expected_ack_seq = req_seq;
3537 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003538
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003539 if (tx_seq == chan->expected_tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003540 goto expected;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003541
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003542 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003543 if (tx_seq_offset < 0)
3544 tx_seq_offset += 64;
3545
3546 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003547 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003548 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003549 goto drop;
3550 }
3551
Mat Martineaue6949282011-06-03 16:21:10 -07003552 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003553 goto drop;
3554
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003555 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003556 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003557
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003558 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003559 struct srej_list, list);
3560 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003561 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003562 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003563
3564 list_del(&first->list);
3565 kfree(first);
3566
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003567 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003568 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003569 chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
3570 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003571 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003572 }
3573 } else {
3574 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003575
3576 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003577 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003578 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003579
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003580 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003581 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003582 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003583 return 0;
3584 }
3585 }
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003586 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003587 }
3588 } else {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003589 expected_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003590 (chan->expected_tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003591 if (expected_tx_seq_offset < 0)
3592 expected_tx_seq_offset += 64;
3593
3594 /* duplicated tx_seq */
3595 if (tx_seq_offset < expected_tx_seq_offset)
3596 goto drop;
3597
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003598 chan->conn_state |= L2CAP_CONN_SREJ_SENT;
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003599
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003600 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003601
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003602 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003603 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003604
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003605 __skb_queue_head_init(&chan->srej_q);
3606 __skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003607 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003608
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003609 chan->conn_state |= L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003610
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003611 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003612
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003613 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003614 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003615 return 0;
3616
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003617expected:
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003618 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003619
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003620 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003621 bt_cb(skb)->tx_seq = tx_seq;
3622 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003623 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003624 return 0;
3625 }
3626
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003627 err = l2cap_push_rx_skb(chan, skb, rx_control);
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003628 if (err < 0)
3629 return 0;
3630
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003631 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003632 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3633 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003634 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003635 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003636 }
3637
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003638 __set_ack_timer(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003639
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003640 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3641 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003642 l2cap_send_ack(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003643
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003644 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003645
3646drop:
3647 kfree_skb(skb);
3648 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003649}
3650
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003651static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003652{
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003653 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003654 rx_control);
3655
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003656 chan->expected_ack_seq = __get_reqseq(rx_control);
3657 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003658
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003659 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003660 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3661 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
3662 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003663 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003664 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003665
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003666 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3667 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003668 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003669 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003670 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003671
3672 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003673 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003674
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003675 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3676 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003677 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003678 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003679
3680 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003681 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003682 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003683 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003684
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003685 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3686 if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
3687 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003688 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003689 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003690 }
3691}
3692
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003693static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003694{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003695 u8 tx_seq = __get_reqseq(rx_control);
3696
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003697 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003698
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003699 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003700
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003701 chan->expected_ack_seq = tx_seq;
3702 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003703
3704 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003705 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3706 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003707 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003708 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003709 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003710 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003711
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003712 if (chan->conn_state & L2CAP_CONN_WAIT_F)
3713 chan->conn_state |= L2CAP_CONN_REJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003714 }
3715}
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003716static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003717{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003718 u8 tx_seq = __get_reqseq(rx_control);
3719
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003720 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003721
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003722 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003723
3724 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003725 chan->expected_ack_seq = tx_seq;
3726 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003727
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003728 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3729 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003730
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003731 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003732
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003733 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003734 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003735 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003736 }
3737 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003738 if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003739 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003740 chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
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);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003743 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003744 l2cap_retransmit_one_frame(chan, tx_seq);
3745 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003746 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003747 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003748 }
3749 }
3750}
3751
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003752static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003753{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003754 u8 tx_seq = __get_reqseq(rx_control);
3755
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003756 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003757
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003758 chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003759 chan->expected_ack_seq = tx_seq;
3760 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003761
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003762 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003763 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003764
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003765 if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003766 __clear_retrans_timer(chan);
Gustavo F. Padovana2e12a22010-05-05 19:58:27 -03003767 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003768 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003769 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003770 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003771
3772 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003773 l2cap_send_srejtail(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003774 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003775 l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003776}
3777
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003778static 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 -03003779{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003780 BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003781
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003782 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003783 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003784 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003785 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003786 __set_retrans_timer(chan);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003787 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003788 }
3789
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003790 switch (rx_control & L2CAP_CTRL_SUPERVISE) {
3791 case L2CAP_SUPER_RCV_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003792 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003793 break;
3794
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003795 case L2CAP_SUPER_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003796 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003797 break;
3798
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003799 case L2CAP_SUPER_SELECT_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003800 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003801 break;
3802
3803 case L2CAP_SUPER_RCV_NOT_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003804 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003805 break;
3806 }
3807
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03003808 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003809 return 0;
3810}
3811
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003812static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
3813{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003814 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003815 u16 control;
3816 u8 req_seq;
3817 int len, next_tx_seq_offset, req_seq_offset;
3818
3819 control = get_unaligned_le16(skb->data);
3820 skb_pull(skb, 2);
3821 len = skb->len;
3822
3823 /*
3824 * We can just drop the corrupted I-frame here.
3825 * Receiver will miss it and start proper recovery
3826 * procedures and ask retransmission.
3827 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003828 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003829 goto drop;
3830
3831 if (__is_sar_start(control) && __is_iframe(control))
3832 len -= 2;
3833
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003834 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003835 len -= 2;
3836
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003837 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003838 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003839 goto drop;
3840 }
3841
3842 req_seq = __get_reqseq(control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003843 req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003844 if (req_seq_offset < 0)
3845 req_seq_offset += 64;
3846
3847 next_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003848 (chan->next_tx_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003849 if (next_tx_seq_offset < 0)
3850 next_tx_seq_offset += 64;
3851
3852 /* check for invalid req-seq */
3853 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003854 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003855 goto drop;
3856 }
3857
3858 if (__is_iframe(control)) {
3859 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003860 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003861 goto drop;
3862 }
3863
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003864 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003865 } else {
3866 if (len != 0) {
3867 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003868 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003869 goto drop;
3870 }
3871
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003872 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003873 }
3874
3875 return 0;
3876
3877drop:
3878 kfree_skb(skb);
3879 return 0;
3880}
3881
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
3883{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003884 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07003885 struct sock *sk = NULL;
Nathan Holstein51893f82010-06-09 15:46:25 -04003886 u16 control;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003887 u8 tx_seq;
3888 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003890 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003891 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 BT_DBG("unknown cid 0x%4.4x", cid);
3893 goto drop;
3894 }
3895
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003896 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003897
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003898 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003900 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 goto drop;
3902
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003903 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003904 case L2CAP_MODE_BASIC:
3905 /* If socket recv buffers overflows we drop data here
3906 * which is *bad* because L2CAP has to be reliable.
3907 * But we don't have any other choice. L2CAP doesn't
3908 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003910 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003911 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003913 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003914 goto done;
3915 break;
3916
3917 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003918 if (!sock_owned_by_user(sk)) {
3919 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003920 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003921 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003922 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003923 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003924
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02003925 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003926
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003927 case L2CAP_MODE_STREAMING:
3928 control = get_unaligned_le16(skb->data);
3929 skb_pull(skb, 2);
3930 len = skb->len;
3931
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003932 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03003933 goto drop;
3934
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003935 if (__is_sar_start(control))
3936 len -= 2;
3937
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003938 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003939 len -= 2;
3940
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003941 if (len > chan->mps || len < 0 || __is_sframe(control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003942 goto drop;
3943
3944 tx_seq = __get_txseq(control);
3945
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003946 if (chan->expected_tx_seq == tx_seq)
3947 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003948 else
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003949 chan->expected_tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003950
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003951 l2cap_streaming_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003952
3953 goto done;
3954
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003955 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003956 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003957 break;
3958 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959
3960drop:
3961 kfree_skb(skb);
3962
3963done:
Marcel Holtmann01394182006-07-03 10:02:46 +02003964 if (sk)
3965 bh_unlock_sock(sk);
3966
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 return 0;
3968}
3969
Al Viro8e036fc2007-07-29 00:16:36 -07003970static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003972 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003973 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003975 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
3976 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 goto drop;
3978
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003979 sk = chan->sk;
3980
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00003981 bh_lock_sock(sk);
3982
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 BT_DBG("sk %p, len %d", sk, skb->len);
3984
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003985 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 goto drop;
3987
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003988 if (l2cap_pi(sk)->chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 goto drop;
3990
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003991 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 goto done;
3993
3994drop:
3995 kfree_skb(skb);
3996
3997done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03003998 if (sk)
3999 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 return 0;
4001}
4002
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004003static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4004{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004005 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004006 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004007
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004008 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4009 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004010 goto drop;
4011
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004012 sk = chan->sk;
4013
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004014 bh_lock_sock(sk);
4015
4016 BT_DBG("sk %p, len %d", sk, skb->len);
4017
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004018 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004019 goto drop;
4020
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004021 if (l2cap_pi(sk)->chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004022 goto drop;
4023
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004024 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004025 goto done;
4026
4027drop:
4028 kfree_skb(skb);
4029
4030done:
4031 if (sk)
4032 bh_unlock_sock(sk);
4033 return 0;
4034}
4035
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4037{
4038 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004039 u16 cid, len;
4040 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041
4042 skb_pull(skb, L2CAP_HDR_SIZE);
4043 cid = __le16_to_cpu(lh->cid);
4044 len = __le16_to_cpu(lh->len);
4045
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004046 if (len != skb->len) {
4047 kfree_skb(skb);
4048 return;
4049 }
4050
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4052
4053 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004054 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004055 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056 l2cap_sig_channel(conn, skb);
4057 break;
4058
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004059 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004060 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 skb_pull(skb, 2);
4062 l2cap_conless_channel(conn, psm, skb);
4063 break;
4064
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004065 case L2CAP_CID_LE_DATA:
4066 l2cap_att_channel(conn, cid, skb);
4067 break;
4068
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004069 case L2CAP_CID_SMP:
4070 if (smp_sig_channel(conn, skb))
4071 l2cap_conn_del(conn->hcon, EACCES);
4072 break;
4073
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 default:
4075 l2cap_data_channel(conn, cid, skb);
4076 break;
4077 }
4078}
4079
4080/* ---- L2CAP interface with lower layer (HCI) ---- */
4081
4082static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4083{
4084 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004085 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086
4087 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004088 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089
4090 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4091
4092 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004093 read_lock(&chan_list_lock);
4094 list_for_each_entry(c, &chan_list, global_l) {
4095 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004096
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004097 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 continue;
4099
4100 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004101 lm1 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004102 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004103 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004105 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4106 lm2 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004107 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004108 lm2 |= HCI_LM_MASTER;
4109 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004111 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112
4113 return exact ? lm1 : lm2;
4114}
4115
4116static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4117{
Marcel Holtmann01394182006-07-03 10:02:46 +02004118 struct l2cap_conn *conn;
4119
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4121
Ville Tervoacd7d372011-02-10 22:38:49 -03004122 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004123 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004124
4125 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126 conn = l2cap_conn_add(hcon, status);
4127 if (conn)
4128 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004129 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 l2cap_conn_del(hcon, bt_err(status));
4131
4132 return 0;
4133}
4134
Marcel Holtmann2950f212009-02-12 14:02:50 +01004135static int l2cap_disconn_ind(struct hci_conn *hcon)
4136{
4137 struct l2cap_conn *conn = hcon->l2cap_data;
4138
4139 BT_DBG("hcon %p", hcon);
4140
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004141 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004142 return 0x13;
4143
4144 return conn->disc_reason;
4145}
4146
4147static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148{
4149 BT_DBG("hcon %p reason %d", hcon, reason);
4150
Ville Tervoacd7d372011-02-10 22:38:49 -03004151 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004152 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153
4154 l2cap_conn_del(hcon, bt_err(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004155
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 return 0;
4157}
4158
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004159static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004160{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004161 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004162 return;
4163
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004164 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004165 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004166 __clear_chan_timer(chan);
4167 __set_chan_timer(chan, HZ * 5);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004168 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004169 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004170 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004171 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004172 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004173 }
4174}
4175
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004176static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004178 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004179 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
Marcel Holtmann01394182006-07-03 10:02:46 +02004181 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004183
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 BT_DBG("conn %p", conn);
4185
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004186 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004188 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004189 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004190
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 bh_lock_sock(sk);
4192
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004193 BT_DBG("chan->scid %d", chan->scid);
4194
4195 if (chan->scid == L2CAP_CID_LE_DATA) {
4196 if (!status && encrypt) {
4197 chan->sec_level = hcon->sec_level;
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03004198 del_timer(&conn->security_timer);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004199 l2cap_chan_ready(sk);
4200 }
4201
4202 bh_unlock_sock(sk);
4203 continue;
4204 }
4205
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004206 if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004207 bh_unlock_sock(sk);
4208 continue;
4209 }
4210
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004211 if (!status && (chan->state == BT_CONNECTED ||
4212 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004213 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004214 bh_unlock_sock(sk);
4215 continue;
4216 }
4217
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004218 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004219 if (!status) {
4220 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004221 req.scid = cpu_to_le16(chan->scid);
4222 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004223
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004224 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004225 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004226
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004227 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004228 L2CAP_CONN_REQ, sizeof(req), &req);
4229 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004230 __clear_chan_timer(chan);
4231 __set_chan_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004232 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004233 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004234 struct l2cap_conn_rsp rsp;
4235 __u16 result;
4236
4237 if (!status) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004238 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004239 result = L2CAP_CR_SUCCESS;
4240 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004241 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004242 __set_chan_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004243 result = L2CAP_CR_SEC_BLOCK;
4244 }
4245
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004246 rsp.scid = cpu_to_le16(chan->dcid);
4247 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004248 rsp.result = cpu_to_le16(result);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02004249 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004250 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4251 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 }
4253
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 bh_unlock_sock(sk);
4255 }
4256
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004257 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004258
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259 return 0;
4260}
4261
4262static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4263{
4264 struct l2cap_conn *conn = hcon->l2cap_data;
4265
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004266 if (!conn)
4267 conn = l2cap_conn_add(hcon, 0);
4268
4269 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 goto drop;
4271
4272 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4273
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004274 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004276 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004277 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004278 int len;
4279
4280 if (conn->rx_len) {
4281 BT_ERR("Unexpected start frame (len %d)", skb->len);
4282 kfree_skb(conn->rx_skb);
4283 conn->rx_skb = NULL;
4284 conn->rx_len = 0;
4285 l2cap_conn_unreliable(conn, ECOMM);
4286 }
4287
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004288 /* Start fragment always begin with Basic L2CAP header */
4289 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004290 BT_ERR("Frame is too short (len %d)", skb->len);
4291 l2cap_conn_unreliable(conn, ECOMM);
4292 goto drop;
4293 }
4294
4295 hdr = (struct l2cap_hdr *) skb->data;
4296 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004297 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298
4299 if (len == skb->len) {
4300 /* Complete frame received */
4301 l2cap_recv_frame(conn, skb);
4302 return 0;
4303 }
4304
4305 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4306
4307 if (skb->len > len) {
4308 BT_ERR("Frame is too long (len %d, expected len %d)",
4309 skb->len, len);
4310 l2cap_conn_unreliable(conn, ECOMM);
4311 goto drop;
4312 }
4313
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004314 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004315
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004316 if (chan && chan->sk) {
4317 struct sock *sk = chan->sk;
4318
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004319 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004320 BT_ERR("Frame exceeding recv MTU (len %d, "
4321 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004322 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004323 bh_unlock_sock(sk);
4324 l2cap_conn_unreliable(conn, ECOMM);
4325 goto drop;
4326 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004327 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004328 }
4329
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004331 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4332 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 goto drop;
4334
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004335 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004336 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 conn->rx_len = len - skb->len;
4338 } else {
4339 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4340
4341 if (!conn->rx_len) {
4342 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4343 l2cap_conn_unreliable(conn, ECOMM);
4344 goto drop;
4345 }
4346
4347 if (skb->len > conn->rx_len) {
4348 BT_ERR("Fragment is too long (len %d, expected %d)",
4349 skb->len, conn->rx_len);
4350 kfree_skb(conn->rx_skb);
4351 conn->rx_skb = NULL;
4352 conn->rx_len = 0;
4353 l2cap_conn_unreliable(conn, ECOMM);
4354 goto drop;
4355 }
4356
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004357 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004358 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 conn->rx_len -= skb->len;
4360
4361 if (!conn->rx_len) {
4362 /* Complete frame received */
4363 l2cap_recv_frame(conn, conn->rx_skb);
4364 conn->rx_skb = NULL;
4365 }
4366 }
4367
4368drop:
4369 kfree_skb(skb);
4370 return 0;
4371}
4372
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004373static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004375 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004377 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004379 list_for_each_entry(c, &chan_list, global_l) {
4380 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004382 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 +01004383 batostr(&bt_sk(sk)->src),
4384 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004385 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004386 c->scid, c->dcid, c->imtu, c->omtu,
4387 c->sec_level, c->mode);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004390 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004391
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004392 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393}
4394
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004395static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4396{
4397 return single_open(file, l2cap_debugfs_show, inode->i_private);
4398}
4399
4400static const struct file_operations l2cap_debugfs_fops = {
4401 .open = l2cap_debugfs_open,
4402 .read = seq_read,
4403 .llseek = seq_lseek,
4404 .release = single_release,
4405};
4406
4407static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408
Linus Torvalds1da177e2005-04-16 15:20:36 -07004409static struct hci_proto l2cap_hci_proto = {
4410 .name = "L2CAP",
4411 .id = HCI_PROTO_L2CAP,
4412 .connect_ind = l2cap_connect_ind,
4413 .connect_cfm = l2cap_connect_cfm,
4414 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004415 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004416 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 .recv_acldata = l2cap_recv_acldata
4418};
4419
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004420int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421{
4422 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004423
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004424 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 if (err < 0)
4426 return err;
4427
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004428 _busy_wq = create_singlethread_workqueue("l2cap");
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004429 if (!_busy_wq) {
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004430 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431 goto error;
4432 }
4433
4434 err = hci_register_proto(&l2cap_hci_proto);
4435 if (err < 0) {
4436 BT_ERR("L2CAP protocol registration failed");
4437 bt_sock_unregister(BTPROTO_L2CAP);
4438 goto error;
4439 }
4440
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004441 if (bt_debugfs) {
4442 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4443 bt_debugfs, NULL, &l2cap_debugfs_fops);
4444 if (!l2cap_debugfs)
4445 BT_ERR("Failed to create L2CAP debug file");
4446 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 return 0;
4449
4450error:
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004451 destroy_workqueue(_busy_wq);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004452 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453 return err;
4454}
4455
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004456void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004458 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004460 flush_workqueue(_busy_wq);
4461 destroy_workqueue(_busy_wq);
4462
Linus Torvalds1da177e2005-04-16 15:20:36 -07004463 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4464 BT_ERR("L2CAP protocol unregistration failed");
4465
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004466 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467}
4468
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004469module_param(disable_ertm, bool, 0644);
4470MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");