blob: aa33499798a670042e5a1dd6620b0420c0152b68 [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;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +030060int enable_hs;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020061
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070062static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Marcel Holtmanne1027a72009-02-09 09:18:02 +010063static u8 l2cap_fixed_chan[8] = { 0x02, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Johannes Bergb5ad8b72011-06-01 08:54:45 +020065static LIST_HEAD(chan_list);
66static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
69 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030070static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
71 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030072static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030073static void l2cap_send_disconn_req(struct l2cap_conn *conn,
74 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030076static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
77
Marcel Holtmann01394182006-07-03 10:02:46 +020078/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030079
80static inline void chan_hold(struct l2cap_chan *c)
81{
82 atomic_inc(&c->refcnt);
83}
84
85static inline void chan_put(struct l2cap_chan *c)
86{
87 if (atomic_dec_and_test(&c->refcnt))
88 kfree(c);
89}
90
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030091static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020092{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030093 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030094
95 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030096 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030097 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020098 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030099 return NULL;
100
Marcel Holtmann01394182006-07-03 10:02:46 +0200101}
102
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300103static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200104{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300105 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300106
107 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300108 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300109 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200110 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300111 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200112}
113
114/* Find channel with given SCID.
115 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300116static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200117{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300118 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300119
120 read_lock(&conn->chan_lock);
121 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300122 if (c)
123 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300124 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300125 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200126}
127
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300128static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200129{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300130 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300131
132 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300133 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300134 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200135 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300136 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200137}
138
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300139static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200140{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300141 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300142
143 read_lock(&conn->chan_lock);
144 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300145 if (c)
146 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300147 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300148 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200149}
150
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300151static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300152{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300153 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300154
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300155 list_for_each_entry(c, &chan_list, global_l) {
156 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300157 goto found;
158 }
159
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300160 c = NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300161found:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300162 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300163}
164
165int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
166{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300167 int err;
168
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300169 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300170
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300171 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300172 err = -EADDRINUSE;
173 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300174 }
175
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300176 if (psm) {
177 chan->psm = psm;
178 chan->sport = psm;
179 err = 0;
180 } else {
181 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300182
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300183 err = -EINVAL;
184 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300185 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300186 chan->psm = cpu_to_le16(p);
187 chan->sport = cpu_to_le16(p);
188 err = 0;
189 break;
190 }
191 }
192
193done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300194 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300195 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300196}
197
198int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
199{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300200 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300201
202 chan->scid = scid;
203
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300204 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300205
206 return 0;
207}
208
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300209static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200210{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300211 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200212
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300213 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300214 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200215 return cid;
216 }
217
218 return 0;
219}
220
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300221static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300222{
Mat Martineau774e5652011-06-29 14:35:20 -0700223 BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300224
Mat Martineau942ecc92011-06-29 14:35:21 -0700225 if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
Mat Martineau774e5652011-06-29 14:35:20 -0700226 chan_hold(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300227}
228
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300229static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300230{
Mat Martineau774e5652011-06-29 14:35:20 -0700231 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300232
Mat Martineau774e5652011-06-29 14:35:20 -0700233 if (timer_pending(timer) && del_timer(timer))
234 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300235}
236
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300237static void l2cap_state_change(struct l2cap_chan *chan, int state)
238{
239 chan->state = state;
240 chan->ops->state_change(chan->data, state);
241}
242
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300243static void l2cap_chan_timeout(unsigned long arg)
244{
245 struct l2cap_chan *chan = (struct l2cap_chan *) arg;
246 struct sock *sk = chan->sk;
247 int reason;
248
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300249 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300250
251 bh_lock_sock(sk);
252
253 if (sock_owned_by_user(sk)) {
254 /* sk is owned by user. Try again later */
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300255 __set_chan_timer(chan, HZ / 5);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300256 bh_unlock_sock(sk);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300257 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300258 return;
259 }
260
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300261 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300262 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300263 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300264 chan->sec_level != BT_SECURITY_SDP)
265 reason = ECONNREFUSED;
266 else
267 reason = ETIMEDOUT;
268
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300269 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300270
271 bh_unlock_sock(sk);
272
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300273 chan->ops->close(chan->data);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300274 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300275}
276
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300277struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200278{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300279 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200280
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300281 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
282 if (!chan)
283 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200284
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300285 chan->sk = sk;
286
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300287 write_lock_bh(&chan_list_lock);
288 list_add(&chan->global_l, &chan_list);
289 write_unlock_bh(&chan_list_lock);
290
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300291 setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
292
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300293 chan->state = BT_OPEN;
294
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300295 atomic_set(&chan->refcnt, 1);
296
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300297 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200298}
299
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300300void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300301{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300302 write_lock_bh(&chan_list_lock);
303 list_del(&chan->global_l);
304 write_unlock_bh(&chan_list_lock);
305
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300306 chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300307}
308
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300309static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200310{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300311 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300312 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200313
Marcel Holtmann2950f212009-02-12 14:02:50 +0100314 conn->disc_reason = 0x13;
315
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300316 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200317
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300318 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300319 if (conn->hcon->type == LE_LINK) {
320 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300321 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300322 chan->scid = L2CAP_CID_LE_DATA;
323 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300324 } else {
325 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300326 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300327 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300328 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300329 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200330 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300331 chan->scid = L2CAP_CID_CONN_LESS;
332 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300333 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200334 } else {
335 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300336 chan->scid = L2CAP_CID_SIGNALING;
337 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300338 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200339 }
340
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300341 chan->local_id = L2CAP_BESTEFFORT_ID;
342 chan->local_stype = L2CAP_SERV_BESTEFFORT;
343 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
344 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
345 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
346 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
347
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300348 chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300349
350 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200351}
352
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900353/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200354 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300355static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200356{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300357 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300358 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200359 struct sock *parent = bt_sk(sk)->parent;
360
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300361 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200362
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300363 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200364
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900365 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300366 /* Delete from channel list */
367 write_lock_bh(&conn->chan_lock);
368 list_del(&chan->list);
369 write_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300370 chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300371
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300372 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200373 hci_conn_put(conn->hcon);
374 }
375
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300376 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200377 sock_set_flag(sk, SOCK_ZAPPED);
378
379 if (err)
380 sk->sk_err = err;
381
382 if (parent) {
383 bt_accept_unlink(sk);
384 parent->sk_data_ready(parent, 0);
385 } else
386 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300387
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300388 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
389 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300390 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300391
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300392 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300393
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300394 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300395 struct srej_list *l, *tmp;
396
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300397 __clear_retrans_timer(chan);
398 __clear_monitor_timer(chan);
399 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300400
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300401 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300402
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300403 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300404 list_del(&l->list);
405 kfree(l);
406 }
407 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200408}
409
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300410static void l2cap_chan_cleanup_listen(struct sock *parent)
411{
412 struct sock *sk;
413
414 BT_DBG("parent %p", parent);
415
416 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300417 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300418 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300419 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300420 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300421 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300422 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300423 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300424 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300425}
426
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300427void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300428{
429 struct l2cap_conn *conn = chan->conn;
430 struct sock *sk = chan->sk;
431
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300432 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300433
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300434 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300435 case BT_LISTEN:
436 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300437
438 l2cap_state_change(chan, BT_CLOSED);
439 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300440 break;
441
442 case BT_CONNECTED:
443 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300444 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300445 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300446 __clear_chan_timer(chan);
447 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300448 l2cap_send_disconn_req(conn, chan, reason);
449 } else
450 l2cap_chan_del(chan, reason);
451 break;
452
453 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300454 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300455 conn->hcon->type == ACL_LINK) {
456 struct l2cap_conn_rsp rsp;
457 __u16 result;
458
459 if (bt_sk(sk)->defer_setup)
460 result = L2CAP_CR_SEC_BLOCK;
461 else
462 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300463 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300464
465 rsp.scid = cpu_to_le16(chan->dcid);
466 rsp.dcid = cpu_to_le16(chan->scid);
467 rsp.result = cpu_to_le16(result);
468 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
469 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
470 sizeof(rsp), &rsp);
471 }
472
473 l2cap_chan_del(chan, reason);
474 break;
475
476 case BT_CONNECT:
477 case BT_DISCONN:
478 l2cap_chan_del(chan, reason);
479 break;
480
481 default:
482 sock_set_flag(sk, SOCK_ZAPPED);
483 break;
484 }
485}
486
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300487static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530488{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300489 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300490 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530491 case BT_SECURITY_HIGH:
492 return HCI_AT_DEDICATED_BONDING_MITM;
493 case BT_SECURITY_MEDIUM:
494 return HCI_AT_DEDICATED_BONDING;
495 default:
496 return HCI_AT_NO_BONDING;
497 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300498 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300499 if (chan->sec_level == BT_SECURITY_LOW)
500 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530501
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300502 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530503 return HCI_AT_NO_BONDING_MITM;
504 else
505 return HCI_AT_NO_BONDING;
506 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300507 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530508 case BT_SECURITY_HIGH:
509 return HCI_AT_GENERAL_BONDING_MITM;
510 case BT_SECURITY_MEDIUM:
511 return HCI_AT_GENERAL_BONDING;
512 default:
513 return HCI_AT_NO_BONDING;
514 }
515 }
516}
517
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200518/* Service level security */
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300519static inline int l2cap_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200520{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300521 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100522 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200523
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300524 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100525
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300526 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200527}
528
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200529static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200530{
531 u8 id;
532
533 /* Get next available identificator.
534 * 1 - 128 are used by kernel.
535 * 129 - 199 are reserved.
536 * 200 - 254 are used by utilities like l2ping, etc.
537 */
538
539 spin_lock_bh(&conn->lock);
540
541 if (++conn->tx_ident > 128)
542 conn->tx_ident = 1;
543
544 id = conn->tx_ident;
545
546 spin_unlock_bh(&conn->lock);
547
548 return id;
549}
550
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300551static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200552{
553 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200554 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200555
556 BT_DBG("code 0x%2.2x", code);
557
558 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300559 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200560
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200561 if (lmp_no_flush_capable(conn->hcon->hdev))
562 flags = ACL_START_NO_FLUSH;
563 else
564 flags = ACL_START;
565
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700566 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
567
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200568 hci_send_acl(conn->hcon, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200569}
570
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300571static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300572{
573 struct sk_buff *skb;
574 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300575 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300576 int count, hlen;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200577 u8 flags;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300578
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300579 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300580 return;
581
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300582 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
583 hlen = L2CAP_EXT_HDR_SIZE;
584 else
585 hlen = L2CAP_ENH_HDR_SIZE;
586
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300587 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300588 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300589
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300590 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300591
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300592 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300593
594 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300595
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300596 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300597 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300598
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300599 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300600 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300601
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300602 skb = bt_skb_alloc(count, GFP_ATOMIC);
603 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300604 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300605
606 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300607 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300608 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300609
610 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300611
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300612 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300613 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
614 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300615 }
616
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200617 if (lmp_no_flush_capable(conn->hcon->hdev))
618 flags = ACL_START_NO_FLUSH;
619 else
620 flags = ACL_START;
621
Andrei Emeltchenko15770b12011-10-11 14:04:33 +0300622 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700623
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300624 hci_send_acl(chan->conn->hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300625}
626
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300627static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300628{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300629 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300630 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300631 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300632 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300633 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300634
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300635 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300636
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300637 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300638}
639
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300640static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300641{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300642 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300643}
644
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300645static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200646{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300647 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200648
649 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100650 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
651 return;
652
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300653 if (l2cap_check_security(chan) &&
654 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200655 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300656 req.scid = cpu_to_le16(chan->scid);
657 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200658
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300659 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300660 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200661
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300662 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
663 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200664 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200665 } else {
666 struct l2cap_info_req req;
667 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
668
669 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
670 conn->info_ident = l2cap_get_ident(conn);
671
672 mod_timer(&conn->info_timer, jiffies +
673 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
674
675 l2cap_send_cmd(conn, conn->info_ident,
676 L2CAP_INFO_REQ, sizeof(req), &req);
677 }
678}
679
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300680static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
681{
682 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300683 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300684 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
685
686 switch (mode) {
687 case L2CAP_MODE_ERTM:
688 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
689 case L2CAP_MODE_STREAMING:
690 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
691 default:
692 return 0x00;
693 }
694}
695
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300696static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300697{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300698 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300699 struct l2cap_disconn_req req;
700
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300701 if (!conn)
702 return;
703
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300704 sk = chan->sk;
705
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300706 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300707 __clear_retrans_timer(chan);
708 __clear_monitor_timer(chan);
709 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300710 }
711
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300712 req.dcid = cpu_to_le16(chan->dcid);
713 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300714 l2cap_send_cmd(conn, l2cap_get_ident(conn),
715 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300716
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300717 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300718 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300719}
720
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200722static void l2cap_conn_start(struct l2cap_conn *conn)
723{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300724 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200725
726 BT_DBG("conn %p", conn);
727
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300728 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200729
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300730 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300731 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300732
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200733 bh_lock_sock(sk);
734
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300735 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200736 bh_unlock_sock(sk);
737 continue;
738 }
739
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300740 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300741 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300742
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300743 if (!l2cap_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300744 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300745 bh_unlock_sock(sk);
746 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200747 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300748
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300749 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
750 && test_bit(CONF_STATE2_DEVICE,
751 &chan->conf_state)) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300752 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300753 * so release the lock */
Gustavo F. Padovan2461daa2011-06-17 12:57:25 -0300754 read_unlock(&conn->chan_lock);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300755 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan2461daa2011-06-17 12:57:25 -0300756 read_lock(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300757 bh_unlock_sock(sk);
758 continue;
759 }
760
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300761 req.scid = cpu_to_le16(chan->scid);
762 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300763
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300764 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300765 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300766
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300767 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
768 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300769
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300770 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200771 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300772 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300773 rsp.scid = cpu_to_le16(chan->dcid);
774 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200775
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300776 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100777 if (bt_sk(sk)->defer_setup) {
778 struct sock *parent = bt_sk(sk)->parent;
779 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
780 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000781 if (parent)
782 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100783
784 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300785 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100786 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
787 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
788 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200789 } else {
790 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
791 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
792 }
793
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300794 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
795 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300796
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300797 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300798 rsp.result != L2CAP_CR_SUCCESS) {
799 bh_unlock_sock(sk);
800 continue;
801 }
802
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300803 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300804 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300805 l2cap_build_conf_req(chan, buf), buf);
806 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200807 }
808
809 bh_unlock_sock(sk);
810 }
811
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300812 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200813}
814
Ville Tervob62f3282011-02-10 22:38:50 -0300815/* Find socket with cid and source bdaddr.
816 * Returns closest match, locked.
817 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300818static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300819{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300820 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300821
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300822 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300823
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300824 list_for_each_entry(c, &chan_list, global_l) {
825 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300826
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300827 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300828 continue;
829
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300830 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300831 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300832 if (!bacmp(&bt_sk(sk)->src, src)) {
833 read_unlock(&chan_list_lock);
834 return c;
835 }
Ville Tervob62f3282011-02-10 22:38:50 -0300836
837 /* Closest match */
838 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300839 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300840 }
841 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300842
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300843 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300844
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300845 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300846}
847
848static void l2cap_le_conn_ready(struct l2cap_conn *conn)
849{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300850 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300851 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300852
853 BT_DBG("");
854
855 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300856 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300857 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300858 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300859 return;
860
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300861 parent = pchan->sk;
862
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300863 bh_lock_sock(parent);
864
Ville Tervob62f3282011-02-10 22:38:50 -0300865 /* Check for backlog size */
866 if (sk_acceptq_is_full(parent)) {
867 BT_DBG("backlog full %d", parent->sk_ack_backlog);
868 goto clean;
869 }
870
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300871 chan = pchan->ops->new_connection(pchan->data);
872 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300873 goto clean;
874
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300875 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300876
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300877 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300878
879 hci_conn_hold(conn->hcon);
880
Ville Tervob62f3282011-02-10 22:38:50 -0300881 bacpy(&bt_sk(sk)->src, conn->src);
882 bacpy(&bt_sk(sk)->dst, conn->dst);
883
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300884 bt_accept_enqueue(parent, sk);
885
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300886 __l2cap_chan_add(conn, chan);
887
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300888 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300889
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300890 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300891 parent->sk_data_ready(parent, 0);
892
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300893 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300894
895clean:
896 bh_unlock_sock(parent);
897}
898
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300899static void l2cap_chan_ready(struct sock *sk)
900{
901 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
902 struct sock *parent = bt_sk(sk)->parent;
903
904 BT_DBG("sk %p, parent %p", sk, parent);
905
906 chan->conf_state = 0;
907 __clear_chan_timer(chan);
908
Vinicius Costa Gomes43f3dc42011-06-20 18:53:18 -0300909 l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300910 sk->sk_state_change(sk);
911
912 if (parent)
913 parent->sk_data_ready(parent, 0);
914}
915
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200916static void l2cap_conn_ready(struct l2cap_conn *conn)
917{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300918 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200919
920 BT_DBG("conn %p", conn);
921
Ville Tervob62f3282011-02-10 22:38:50 -0300922 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
923 l2cap_le_conn_ready(conn);
924
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300925 if (conn->hcon->out && conn->hcon->type == LE_LINK)
926 smp_conn_security(conn, conn->hcon->pending_sec_level);
927
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300928 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200929
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300930 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300931 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300932
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200933 bh_lock_sock(sk);
934
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300935 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300936 if (smp_conn_security(conn, chan->sec_level))
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300937 l2cap_chan_ready(sk);
Ville Tervoacd7d372011-02-10 22:38:49 -0300938
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300939 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300940 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300941 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200942 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300943
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300944 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300945 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200946
947 bh_unlock_sock(sk);
948 }
949
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300950 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200951}
952
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200953/* Notify sockets that we cannot guaranty reliability anymore */
954static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
955{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300956 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200957
958 BT_DBG("conn %p", conn);
959
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300960 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200961
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300962 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300963 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300964
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300965 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200966 sk->sk_err = err;
967 }
968
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300969 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200970}
971
972static void l2cap_info_timeout(unsigned long arg)
973{
974 struct l2cap_conn *conn = (void *) arg;
975
Marcel Holtmann984947d2009-02-06 23:35:19 +0100976 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100977 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100978
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200979 l2cap_conn_start(conn);
980}
981
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300982static void l2cap_conn_del(struct hci_conn *hcon, int err)
983{
984 struct l2cap_conn *conn = hcon->l2cap_data;
985 struct l2cap_chan *chan, *l;
986 struct sock *sk;
987
988 if (!conn)
989 return;
990
991 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
992
993 kfree_skb(conn->rx_skb);
994
995 /* Kill channels */
996 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
997 sk = chan->sk;
998 bh_lock_sock(sk);
999 l2cap_chan_del(chan, err);
1000 bh_unlock_sock(sk);
1001 chan->ops->close(chan->data);
1002 }
1003
1004 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
1005 del_timer_sync(&conn->info_timer);
1006
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001007 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001008 del_timer(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001009 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001010 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001011
1012 hcon->l2cap_data = NULL;
1013 kfree(conn);
1014}
1015
1016static void security_timeout(unsigned long arg)
1017{
1018 struct l2cap_conn *conn = (void *) arg;
1019
1020 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1021}
1022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1024{
Marcel Holtmann01394182006-07-03 10:02:46 +02001025 struct l2cap_conn *conn = hcon->l2cap_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026
Marcel Holtmann01394182006-07-03 10:02:46 +02001027 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 return conn;
1029
Marcel Holtmann01394182006-07-03 10:02:46 +02001030 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1031 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034 hcon->l2cap_data = conn;
1035 conn->hcon = hcon;
1036
Marcel Holtmann01394182006-07-03 10:02:46 +02001037 BT_DBG("hcon %p conn %p", hcon, conn);
1038
Ville Tervoacd7d372011-02-10 22:38:49 -03001039 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1040 conn->mtu = hcon->hdev->le_mtu;
1041 else
1042 conn->mtu = hcon->hdev->acl_mtu;
1043
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 conn->src = &hcon->hdev->bdaddr;
1045 conn->dst = &hcon->dst;
1046
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001047 conn->feat_mask = 0;
1048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001050 rwlock_init(&conn->chan_lock);
1051
1052 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001054 if (hcon->type == LE_LINK)
1055 setup_timer(&conn->security_timer, security_timeout,
1056 (unsigned long) conn);
1057 else
Ville Tervob62f3282011-02-10 22:38:50 -03001058 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +00001059 (unsigned long) conn);
1060
Marcel Holtmann2950f212009-02-12 14:02:50 +01001061 conn->disc_reason = 0x13;
1062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 return conn;
1064}
1065
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001066static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001068 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001069 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001070 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071}
1072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
1075/* Find socket with psm and source bdaddr.
1076 * Returns closest match.
1077 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001078static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001080 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001082 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001083
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001084 list_for_each_entry(c, &chan_list, global_l) {
1085 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001086
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001087 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 continue;
1089
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001090 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001092 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001093 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001094 return c;
1095 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
1097 /* Closest match */
1098 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001099 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 }
1101 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001103 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001104
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001105 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106}
1107
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001108int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001110 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 bdaddr_t *src = &bt_sk(sk)->src;
1112 bdaddr_t *dst = &bt_sk(sk)->dst;
1113 struct l2cap_conn *conn;
1114 struct hci_conn *hcon;
1115 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001116 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001117 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001119 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001120 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001122 hdev = hci_get_route(dst, src);
1123 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 return -EHOSTUNREACH;
1125
1126 hci_dev_lock_bh(hdev);
1127
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001128 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001129
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001130 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001131 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001132 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001133 else
1134 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001135 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001136
Ville Tervo30e76272011-02-22 16:10:53 -03001137 if (IS_ERR(hcon)) {
1138 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
1142 conn = l2cap_conn_add(hcon, 0);
1143 if (!conn) {
1144 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001145 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 goto done;
1147 }
1148
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 /* Update source addr of the socket */
1150 bacpy(src, conn->src);
1151
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001152 l2cap_chan_add(conn, chan);
1153
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001154 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001155 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
1157 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001158 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001159 __clear_chan_timer(chan);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001160 if (l2cap_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001161 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001162 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001163 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 }
1165
Ville Tervo30e76272011-02-22 16:10:53 -03001166 err = 0;
1167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168done:
1169 hci_dev_unlock_bh(hdev);
1170 hci_dev_put(hdev);
1171 return err;
1172}
1173
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001174int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001175{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001176 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001177 DECLARE_WAITQUEUE(wait, current);
1178 int err = 0;
1179 int timeo = HZ/5;
1180
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001181 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001182 set_current_state(TASK_INTERRUPTIBLE);
1183 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001184 if (!timeo)
1185 timeo = HZ/5;
1186
1187 if (signal_pending(current)) {
1188 err = sock_intr_errno(timeo);
1189 break;
1190 }
1191
1192 release_sock(sk);
1193 timeo = schedule_timeout(timeo);
1194 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001195 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001196
1197 err = sock_error(sk);
1198 if (err)
1199 break;
1200 }
1201 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001202 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001203 return err;
1204}
1205
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001206static void l2cap_monitor_timeout(unsigned long arg)
1207{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001208 struct l2cap_chan *chan = (void *) arg;
1209 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001210
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001211 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001212
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001213 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001214 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001215 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001216 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001217 return;
1218 }
1219
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001220 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001221 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001222
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001223 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001224 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001225}
1226
1227static void l2cap_retrans_timeout(unsigned long arg)
1228{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001229 struct l2cap_chan *chan = (void *) arg;
1230 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001231
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001232 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001233
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001234 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001235 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001236 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001237
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001238 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001239
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001240 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001241 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001242}
1243
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001244static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001245{
1246 struct sk_buff *skb;
1247
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001248 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001249 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001250 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001251 break;
1252
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001253 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001254 kfree_skb(skb);
1255
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001256 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001257 }
1258
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001259 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001260 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001261}
1262
Szymon Janc67c9e842011-07-28 16:24:33 +02001263static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001264{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001265 struct hci_conn *hcon = chan->conn->hcon;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001266 u16 flags;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001267
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001268 BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001269
Andrei Emeltchenkod57b0e82011-10-11 14:04:31 +03001270 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
1271 lmp_no_flush_capable(hcon->hdev))
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001272 flags = ACL_START_NO_FLUSH;
1273 else
1274 flags = ACL_START;
1275
Andrei Emeltchenko15770b12011-10-11 14:04:33 +03001276 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001277 hci_send_acl(hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001278}
1279
Szymon Janc67c9e842011-07-28 16:24:33 +02001280static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001281{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001282 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001283 u32 control;
1284 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001285
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001286 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001287 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001288 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001289 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001290
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001291 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001292 fcs = crc16(0, (u8 *)skb->data,
1293 skb->len - L2CAP_FCS_SIZE);
1294 put_unaligned_le16(fcs,
1295 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001296 }
1297
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001298 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001299
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001300 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001301 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001302}
1303
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001304static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001305{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001306 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001307 u16 fcs;
1308 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001309
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001310 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001311 if (!skb)
1312 return;
1313
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001314 do {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001315 if (bt_cb(skb)->tx_seq == tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001316 break;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001317
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001318 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001319 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001320
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001321 } while ((skb = skb_queue_next(&chan->tx_q, skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001322
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001323 if (chan->remote_max_tx &&
1324 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001325 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001326 return;
1327 }
1328
1329 tx_skb = skb_clone(skb, GFP_ATOMIC);
1330 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001331
1332 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001333 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001334
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001335 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001336 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001337
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001338 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001339 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001340
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001341 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001342
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001343 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001344 fcs = crc16(0, (u8 *)tx_skb->data,
1345 tx_skb->len - L2CAP_FCS_SIZE);
1346 put_unaligned_le16(fcs,
1347 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001348 }
1349
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001350 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001351}
1352
Szymon Janc67c9e842011-07-28 16:24:33 +02001353static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001354{
1355 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001356 u16 fcs;
1357 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001358 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001359
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001360 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001361 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001362
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001363 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001364
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001365 if (chan->remote_max_tx &&
1366 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001367 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001368 break;
1369 }
1370
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001371 tx_skb = skb_clone(skb, GFP_ATOMIC);
1372
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001373 bt_cb(skb)->retries++;
1374
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001375 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001376 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001377
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001378 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001379 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001380
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001381 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001382 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001383
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001384 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001385
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001386 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001387 fcs = crc16(0, (u8 *)skb->data,
1388 tx_skb->len - L2CAP_FCS_SIZE);
1389 put_unaligned_le16(fcs, skb->data +
1390 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001391 }
1392
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001393 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001394
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001395 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001396
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001397 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001398
1399 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001400
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301401 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001402 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301403
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001404 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001405
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001406 if (skb_queue_is_last(&chan->tx_q, skb))
1407 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001408 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001409 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001410
1411 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001412 }
1413
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001414 return nsent;
1415}
1416
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001417static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001418{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001419 int ret;
1420
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001421 if (!skb_queue_empty(&chan->tx_q))
1422 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001423
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001424 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001425 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001426 return ret;
1427}
1428
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001429static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001430{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001431 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001432
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001433 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001434
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001435 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001436 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001437 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001438 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001439 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001440 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001441
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001442 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001443 return;
1444
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001445 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001446 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001447}
1448
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001449static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001450{
1451 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001452 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001453
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001454 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001455 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001456
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001457 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001458 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001459
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001460 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001461}
1462
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001463static 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 -07001464{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001465 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001466 struct sk_buff **frag;
1467 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001469 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001470 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471
1472 sent += count;
1473 len -= count;
1474
1475 /* Continuation fragments (no L2CAP header) */
1476 frag = &skb_shinfo(skb)->frag_list;
1477 while (len) {
1478 count = min_t(unsigned int, conn->mtu, len);
1479
1480 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1481 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001482 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001483 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1484 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485
1486 sent += count;
1487 len -= count;
1488
1489 frag = &(*frag)->next;
1490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491
1492 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001493}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
Szymon Janc67c9e842011-07-28 16:24:33 +02001495static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001496{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001497 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001498 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001499 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001500 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001501 struct l2cap_hdr *lh;
1502
1503 BT_DBG("sk %p len %d", sk, (int)len);
1504
1505 count = min_t(unsigned int, (conn->mtu - hlen), len);
1506 skb = bt_skb_send_alloc(sk, count + hlen,
1507 msg->msg_flags & MSG_DONTWAIT, &err);
1508 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001509 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001510
1511 /* Create L2CAP header */
1512 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001513 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001514 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001515 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001516
1517 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1518 if (unlikely(err < 0)) {
1519 kfree_skb(skb);
1520 return ERR_PTR(err);
1521 }
1522 return skb;
1523}
1524
Szymon Janc67c9e842011-07-28 16:24:33 +02001525static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001526{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001527 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001528 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001529 struct sk_buff *skb;
1530 int err, count, hlen = L2CAP_HDR_SIZE;
1531 struct l2cap_hdr *lh;
1532
1533 BT_DBG("sk %p len %d", sk, (int)len);
1534
1535 count = min_t(unsigned int, (conn->mtu - hlen), len);
1536 skb = bt_skb_send_alloc(sk, count + hlen,
1537 msg->msg_flags & MSG_DONTWAIT, &err);
1538 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001539 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001540
1541 /* Create L2CAP header */
1542 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001543 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001544 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1545
1546 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1547 if (unlikely(err < 0)) {
1548 kfree_skb(skb);
1549 return ERR_PTR(err);
1550 }
1551 return skb;
1552}
1553
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001554static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1555 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001556 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001557{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001558 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001559 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001560 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001561 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001562 struct l2cap_hdr *lh;
1563
1564 BT_DBG("sk %p len %d", sk, (int)len);
1565
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001566 if (!conn)
1567 return ERR_PTR(-ENOTCONN);
1568
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001569 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1570 hlen = L2CAP_EXT_HDR_SIZE;
1571 else
1572 hlen = L2CAP_ENH_HDR_SIZE;
1573
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001574 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001575 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001576
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001577 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001578 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001579
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001580 count = min_t(unsigned int, (conn->mtu - hlen), len);
1581 skb = bt_skb_send_alloc(sk, count + hlen,
1582 msg->msg_flags & MSG_DONTWAIT, &err);
1583 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001584 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001585
1586 /* Create L2CAP header */
1587 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001588 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001589 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001590
1591 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1592
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001593 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001594 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001595
1596 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1597 if (unlikely(err < 0)) {
1598 kfree_skb(skb);
1599 return ERR_PTR(err);
1600 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001601
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001602 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001603 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001604
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001605 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001606 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607}
1608
Szymon Janc67c9e842011-07-28 16:24:33 +02001609static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001610{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001611 struct sk_buff *skb;
1612 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001613 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001614 size_t size = 0;
1615
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001616 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001617 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001618 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001619 if (IS_ERR(skb))
1620 return PTR_ERR(skb);
1621
1622 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001623 len -= chan->remote_mps;
1624 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001625
1626 while (len > 0) {
1627 size_t buflen;
1628
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001629 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001630 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001631 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001632 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001633 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001634 buflen = len;
1635 }
1636
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001637 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001638 if (IS_ERR(skb)) {
1639 skb_queue_purge(&sar_queue);
1640 return PTR_ERR(skb);
1641 }
1642
1643 __skb_queue_tail(&sar_queue, skb);
1644 len -= buflen;
1645 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001646 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001647 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1648 if (chan->tx_send_head == NULL)
1649 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001650
1651 return size;
1652}
1653
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001654int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
1655{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001656 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001657 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001658 int err;
1659
1660 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001661 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001662 skb = l2cap_create_connless_pdu(chan, msg, len);
1663 if (IS_ERR(skb))
1664 return PTR_ERR(skb);
1665
1666 l2cap_do_send(chan, skb);
1667 return len;
1668 }
1669
1670 switch (chan->mode) {
1671 case L2CAP_MODE_BASIC:
1672 /* Check outgoing MTU */
1673 if (len > chan->omtu)
1674 return -EMSGSIZE;
1675
1676 /* Create a basic PDU */
1677 skb = l2cap_create_basic_pdu(chan, msg, len);
1678 if (IS_ERR(skb))
1679 return PTR_ERR(skb);
1680
1681 l2cap_do_send(chan, skb);
1682 err = len;
1683 break;
1684
1685 case L2CAP_MODE_ERTM:
1686 case L2CAP_MODE_STREAMING:
1687 /* Entire SDU fits into one PDU */
1688 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001689 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001690 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1691 0);
1692 if (IS_ERR(skb))
1693 return PTR_ERR(skb);
1694
1695 __skb_queue_tail(&chan->tx_q, skb);
1696
1697 if (chan->tx_send_head == NULL)
1698 chan->tx_send_head = skb;
1699
1700 } else {
1701 /* Segment SDU into multiples PDUs */
1702 err = l2cap_sar_segment_sdu(chan, msg, len);
1703 if (err < 0)
1704 return err;
1705 }
1706
1707 if (chan->mode == L2CAP_MODE_STREAMING) {
1708 l2cap_streaming_send(chan);
1709 err = len;
1710 break;
1711 }
1712
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001713 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1714 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001715 err = len;
1716 break;
1717 }
1718
1719 err = l2cap_ertm_send(chan);
1720 if (err >= 0)
1721 err = len;
1722
1723 break;
1724
1725 default:
1726 BT_DBG("bad state %1.1x", chan->mode);
1727 err = -EBADFD;
1728 }
1729
1730 return err;
1731}
1732
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733/* Copy frame to all raw sockets on that connection */
1734static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1735{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001737 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738
1739 BT_DBG("conn %p", conn);
1740
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001741 read_lock(&conn->chan_lock);
1742 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001743 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001744 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745 continue;
1746
1747 /* Don't send frame to the socket it came from */
1748 if (skb->sk == sk)
1749 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001750 nskb = skb_clone(skb, GFP_ATOMIC);
1751 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 continue;
1753
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001754 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 kfree_skb(nskb);
1756 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001757 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758}
1759
1760/* ---- L2CAP signalling commands ---- */
1761static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1762 u8 code, u8 ident, u16 dlen, void *data)
1763{
1764 struct sk_buff *skb, **frag;
1765 struct l2cap_cmd_hdr *cmd;
1766 struct l2cap_hdr *lh;
1767 int len, count;
1768
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001769 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1770 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
1772 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1773 count = min_t(unsigned int, conn->mtu, len);
1774
1775 skb = bt_skb_alloc(count, GFP_ATOMIC);
1776 if (!skb)
1777 return NULL;
1778
1779 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001780 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001781
1782 if (conn->hcon->type == LE_LINK)
1783 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1784 else
1785 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786
1787 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1788 cmd->code = code;
1789 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001790 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791
1792 if (dlen) {
1793 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1794 memcpy(skb_put(skb, count), data, count);
1795 data += count;
1796 }
1797
1798 len -= skb->len;
1799
1800 /* Continuation fragments (no L2CAP header) */
1801 frag = &skb_shinfo(skb)->frag_list;
1802 while (len) {
1803 count = min_t(unsigned int, conn->mtu, len);
1804
1805 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1806 if (!*frag)
1807 goto fail;
1808
1809 memcpy(skb_put(*frag, count), data, count);
1810
1811 len -= count;
1812 data += count;
1813
1814 frag = &(*frag)->next;
1815 }
1816
1817 return skb;
1818
1819fail:
1820 kfree_skb(skb);
1821 return NULL;
1822}
1823
1824static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1825{
1826 struct l2cap_conf_opt *opt = *ptr;
1827 int len;
1828
1829 len = L2CAP_CONF_OPT_SIZE + opt->len;
1830 *ptr += len;
1831
1832 *type = opt->type;
1833 *olen = opt->len;
1834
1835 switch (opt->len) {
1836 case 1:
1837 *val = *((u8 *) opt->val);
1838 break;
1839
1840 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001841 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 break;
1843
1844 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001845 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 break;
1847
1848 default:
1849 *val = (unsigned long) opt->val;
1850 break;
1851 }
1852
1853 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1854 return len;
1855}
1856
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1858{
1859 struct l2cap_conf_opt *opt = *ptr;
1860
1861 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1862
1863 opt->type = type;
1864 opt->len = len;
1865
1866 switch (len) {
1867 case 1:
1868 *((u8 *) opt->val) = val;
1869 break;
1870
1871 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001872 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 break;
1874
1875 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001876 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001877 break;
1878
1879 default:
1880 memcpy(opt->val, (void *) val, len);
1881 break;
1882 }
1883
1884 *ptr += L2CAP_CONF_OPT_SIZE + len;
1885}
1886
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001887static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1888{
1889 struct l2cap_conf_efs efs;
1890
1891 switch(chan->mode) {
1892 case L2CAP_MODE_ERTM:
1893 efs.id = chan->local_id;
1894 efs.stype = chan->local_stype;
1895 efs.msdu = cpu_to_le16(chan->local_msdu);
1896 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1897 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1898 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1899 break;
1900
1901 case L2CAP_MODE_STREAMING:
1902 efs.id = 1;
1903 efs.stype = L2CAP_SERV_BESTEFFORT;
1904 efs.msdu = cpu_to_le16(chan->local_msdu);
1905 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1906 efs.acc_lat = 0;
1907 efs.flush_to = 0;
1908 break;
1909
1910 default:
1911 return;
1912 }
1913
1914 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
1915 (unsigned long) &efs);
1916}
1917
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001918static void l2cap_ack_timeout(unsigned long arg)
1919{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001920 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001921
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001922 bh_lock_sock(chan->sk);
1923 l2cap_send_ack(chan);
1924 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001925}
1926
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001927static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001928{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001929 struct sock *sk = chan->sk;
1930
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001931 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001932 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001933 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001934 chan->num_acked = 0;
1935 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001936
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001937 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1938 (unsigned long) chan);
1939 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1940 (unsigned long) chan);
1941 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001942
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001943 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001944
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001945 INIT_LIST_HEAD(&chan->srej_l);
1946
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001947
1948 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001949}
1950
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001951static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1952{
1953 switch (mode) {
1954 case L2CAP_MODE_STREAMING:
1955 case L2CAP_MODE_ERTM:
1956 if (l2cap_mode_supported(mode, remote_feat_mask))
1957 return mode;
1958 /* fall through */
1959 default:
1960 return L2CAP_MODE_BASIC;
1961 }
1962}
1963
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001964static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
1965{
1966 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
1967}
1968
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001969static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
1970{
1971 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
1972}
1973
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001974static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
1975{
1976 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001977 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001978 /* use extended control field */
1979 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001980 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
1981 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001982 chan->tx_win = min_t(u16, chan->tx_win,
1983 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001984 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
1985 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001986}
1987
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03001988static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001991 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 void *ptr = req->data;
1993
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001994 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001996 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001997 goto done;
1998
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001999 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002000 case L2CAP_MODE_STREAMING:
2001 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002002 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002003 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002004
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002005 if (__l2cap_efs_supported(chan))
2006 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2007
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002008 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002009 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002010 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002011 break;
2012 }
2013
2014done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002015 if (chan->imtu != L2CAP_DEFAULT_MTU)
2016 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002017
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002018 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002019 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002020 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2021 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002022 break;
2023
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002024 rfc.mode = L2CAP_MODE_BASIC;
2025 rfc.txwin_size = 0;
2026 rfc.max_transmit = 0;
2027 rfc.retrans_timeout = 0;
2028 rfc.monitor_timeout = 0;
2029 rfc.max_pdu_size = 0;
2030
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002031 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2032 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002033 break;
2034
2035 case L2CAP_MODE_ERTM:
2036 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002037 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002038 rfc.retrans_timeout = 0;
2039 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03002040 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002041 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
2042 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002043
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002044 l2cap_txwin_setup(chan);
2045
2046 rfc.txwin_size = min_t(u16, chan->tx_win,
2047 L2CAP_DEFAULT_TX_WINDOW);
2048
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002049 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2050 (unsigned long) &rfc);
2051
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002052 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2053 l2cap_add_opt_efs(&ptr, chan);
2054
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002055 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002056 break;
2057
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002058 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002059 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002060 chan->fcs = L2CAP_FCS_NONE;
2061 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002062 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002063
2064 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2065 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2066 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002067 break;
2068
2069 case L2CAP_MODE_STREAMING:
2070 rfc.mode = L2CAP_MODE_STREAMING;
2071 rfc.txwin_size = 0;
2072 rfc.max_transmit = 0;
2073 rfc.retrans_timeout = 0;
2074 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03002075 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002076 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
2077 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002078
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002079 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2080 (unsigned long) &rfc);
2081
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002082 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2083 l2cap_add_opt_efs(&ptr, chan);
2084
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002085 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002086 break;
2087
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002088 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002089 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002090 chan->fcs = L2CAP_FCS_NONE;
2091 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002092 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002093 break;
2094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002096 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002097 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
2099 return ptr - data;
2100}
2101
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002102static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002104 struct l2cap_conf_rsp *rsp = data;
2105 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002106 void *req = chan->conf_req;
2107 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002108 int type, hint, olen;
2109 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002110 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Marcel Holtmann861d6882007-10-20 13:37:06 +02002111 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002112 u16 result = L2CAP_CONF_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002114 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002115
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002116 while (len >= L2CAP_CONF_OPT_SIZE) {
2117 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002119 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002120 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002121
2122 switch (type) {
2123 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002124 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002125 break;
2126
2127 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002128 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002129 break;
2130
2131 case L2CAP_CONF_QOS:
2132 break;
2133
Marcel Holtmann6464f352007-10-20 13:39:51 +02002134 case L2CAP_CONF_RFC:
2135 if (olen == sizeof(rfc))
2136 memcpy(&rfc, (void *) val, olen);
2137 break;
2138
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002139 case L2CAP_CONF_FCS:
2140 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002141 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002142
2143 break;
2144
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002145 case L2CAP_CONF_EWS:
2146 if (!enable_hs)
2147 return -ECONNREFUSED;
2148
2149 set_bit(FLAG_EXT_CTRL, &chan->flags);
2150 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002151 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002152 chan->remote_tx_win = val;
2153 break;
2154
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002155 default:
2156 if (hint)
2157 break;
2158
2159 result = L2CAP_CONF_UNKNOWN;
2160 *((u8 *) ptr++) = type;
2161 break;
2162 }
2163 }
2164
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002165 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002166 goto done;
2167
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002168 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002169 case L2CAP_MODE_STREAMING:
2170 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002171 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002172 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002173 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002174 break;
2175 }
2176
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002177 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002178 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002179
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002180 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002181 }
2182
2183done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002184 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002185 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002186 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002187
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002188 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002189 return -ECONNREFUSED;
2190
2191 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2192 sizeof(rfc), (unsigned long) &rfc);
2193 }
2194
2195
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002196 if (result == L2CAP_CONF_SUCCESS) {
2197 /* Configure output options and let the other side know
2198 * which ones we don't like. */
2199
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002200 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2201 result = L2CAP_CONF_UNACCEPT;
2202 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002203 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002204 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002205 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002206 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002207
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002208 switch (rfc.mode) {
2209 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002210 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002211 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002212 break;
2213
2214 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002215 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2216 chan->remote_tx_win = rfc.txwin_size;
2217 else
2218 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2219
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002220 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002221
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002222 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2223 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002224
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002225 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002226
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002227 rfc.retrans_timeout =
2228 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2229 rfc.monitor_timeout =
2230 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002231
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002232 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002233
2234 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2235 sizeof(rfc), (unsigned long) &rfc);
2236
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002237 break;
2238
2239 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002240 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2241 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002242
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002243 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002244
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002245 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002246
2247 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2248 sizeof(rfc), (unsigned long) &rfc);
2249
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002250 break;
2251
2252 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002253 result = L2CAP_CONF_UNACCEPT;
2254
2255 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002256 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002257 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002258
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002259 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002260 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002261 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002262 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002263 rsp->result = cpu_to_le16(result);
2264 rsp->flags = cpu_to_le16(0x0000);
2265
2266 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267}
2268
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002269static 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 -03002270{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002271 struct l2cap_conf_req *req = data;
2272 void *ptr = req->data;
2273 int type, olen;
2274 unsigned long val;
2275 struct l2cap_conf_rfc rfc;
2276
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002277 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002278
2279 while (len >= L2CAP_CONF_OPT_SIZE) {
2280 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2281
2282 switch (type) {
2283 case L2CAP_CONF_MTU:
2284 if (val < L2CAP_DEFAULT_MIN_MTU) {
2285 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002286 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002287 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002288 chan->imtu = val;
2289 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002290 break;
2291
2292 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002293 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002294 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002295 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002296 break;
2297
2298 case L2CAP_CONF_RFC:
2299 if (olen == sizeof(rfc))
2300 memcpy(&rfc, (void *)val, olen);
2301
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002302 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002303 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002304 return -ECONNREFUSED;
2305
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002306 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002307
2308 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2309 sizeof(rfc), (unsigned long) &rfc);
2310 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002311
2312 case L2CAP_CONF_EWS:
2313 chan->tx_win = min_t(u16, val,
2314 L2CAP_DEFAULT_EXT_WINDOW);
2315 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS,
2316 2, chan->tx_win);
2317 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002318 }
2319 }
2320
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002321 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002322 return -ECONNREFUSED;
2323
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002324 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002325
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002326 if (*result == L2CAP_CONF_SUCCESS) {
2327 switch (rfc.mode) {
2328 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002329 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2330 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2331 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002332 break;
2333 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002334 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002335 }
2336 }
2337
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002338 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002339 req->flags = cpu_to_le16(0x0000);
2340
2341 return ptr - data;
2342}
2343
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002344static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345{
2346 struct l2cap_conf_rsp *rsp = data;
2347 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002349 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002350
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002351 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002352 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002353 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354
2355 return ptr - data;
2356}
2357
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002358void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002359{
2360 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002361 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002362 u8 buf[128];
2363
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002364 rsp.scid = cpu_to_le16(chan->dcid);
2365 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002366 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2367 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2368 l2cap_send_cmd(conn, chan->ident,
2369 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2370
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002371 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002372 return;
2373
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002374 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2375 l2cap_build_conf_req(chan, buf), buf);
2376 chan->num_conf_req++;
2377}
2378
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002379static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002380{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002381 int type, olen;
2382 unsigned long val;
2383 struct l2cap_conf_rfc rfc;
2384
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002385 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002386
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002387 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002388 return;
2389
2390 while (len >= L2CAP_CONF_OPT_SIZE) {
2391 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2392
2393 switch (type) {
2394 case L2CAP_CONF_RFC:
2395 if (olen == sizeof(rfc))
2396 memcpy(&rfc, (void *)val, olen);
2397 goto done;
2398 }
2399 }
2400
2401done:
2402 switch (rfc.mode) {
2403 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002404 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2405 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2406 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002407 break;
2408 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002409 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002410 }
2411}
2412
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002413static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2414{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002415 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002416
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002417 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002418 return 0;
2419
2420 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2421 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002422 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002423
2424 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002425 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002426
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002427 l2cap_conn_start(conn);
2428 }
2429
2430 return 0;
2431}
2432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2434{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2436 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002437 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002438 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002439 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
2441 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002442 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
2444 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2445
2446 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002447 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2448 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 result = L2CAP_CR_BAD_PSM;
2450 goto sendresp;
2451 }
2452
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002453 parent = pchan->sk;
2454
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002455 bh_lock_sock(parent);
2456
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002457 /* Check if the ACL is secure enough (if not SDP) */
2458 if (psm != cpu_to_le16(0x0001) &&
2459 !hci_conn_check_link_mode(conn->hcon)) {
Marcel Holtmann2950f212009-02-12 14:02:50 +01002460 conn->disc_reason = 0x05;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002461 result = L2CAP_CR_SEC_BLOCK;
2462 goto response;
2463 }
2464
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 result = L2CAP_CR_NO_MEM;
2466
2467 /* Check for backlog size */
2468 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002469 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 goto response;
2471 }
2472
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002473 chan = pchan->ops->new_connection(pchan->data);
2474 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 goto response;
2476
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002477 sk = chan->sk;
2478
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002479 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480
2481 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002482 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2483 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002485 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 goto response;
2487 }
2488
2489 hci_conn_hold(conn->hcon);
2490
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 bacpy(&bt_sk(sk)->src, conn->src);
2492 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002493 chan->psm = psm;
2494 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002496 bt_accept_enqueue(parent, sk);
2497
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002498 __l2cap_chan_add(conn, chan);
2499
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002500 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002502 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002504 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505
Marcel Holtmann984947d2009-02-06 23:35:19 +01002506 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03002507 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002508 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002509 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002510 result = L2CAP_CR_PEND;
2511 status = L2CAP_CS_AUTHOR_PEND;
2512 parent->sk_data_ready(parent, 0);
2513 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002514 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002515 result = L2CAP_CR_SUCCESS;
2516 status = L2CAP_CS_NO_INFO;
2517 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002518 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002519 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002520 result = L2CAP_CR_PEND;
2521 status = L2CAP_CS_AUTHEN_PEND;
2522 }
2523 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002524 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002525 result = L2CAP_CR_PEND;
2526 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002527 }
2528
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002529 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530
2531response:
2532 bh_unlock_sock(parent);
2533
2534sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002535 rsp.scid = cpu_to_le16(scid);
2536 rsp.dcid = cpu_to_le16(dcid);
2537 rsp.result = cpu_to_le16(result);
2538 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002540
2541 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2542 struct l2cap_info_req info;
2543 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2544
2545 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2546 conn->info_ident = l2cap_get_ident(conn);
2547
2548 mod_timer(&conn->info_timer, jiffies +
2549 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2550
2551 l2cap_send_cmd(conn, conn->info_ident,
2552 L2CAP_INFO_REQ, sizeof(info), &info);
2553 }
2554
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002555 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002556 result == L2CAP_CR_SUCCESS) {
2557 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002558 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002559 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002560 l2cap_build_conf_req(chan, buf), buf);
2561 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002562 }
2563
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 return 0;
2565}
2566
2567static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2568{
2569 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2570 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002571 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 struct sock *sk;
2573 u8 req[128];
2574
2575 scid = __le16_to_cpu(rsp->scid);
2576 dcid = __le16_to_cpu(rsp->dcid);
2577 result = __le16_to_cpu(rsp->result);
2578 status = __le16_to_cpu(rsp->status);
2579
2580 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2581
2582 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002583 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002584 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002585 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002587 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002588 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002589 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 }
2591
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002592 sk = chan->sk;
2593
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594 switch (result) {
2595 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002596 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002597 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002598 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002599 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002600
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002601 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002602 break;
2603
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002605 l2cap_build_conf_req(chan, req), req);
2606 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 break;
2608
2609 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002610 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 break;
2612
2613 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002614 /* don't delete l2cap channel if sk is owned by user */
2615 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002616 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002617 __clear_chan_timer(chan);
2618 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002619 break;
2620 }
2621
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002622 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 break;
2624 }
2625
2626 bh_unlock_sock(sk);
2627 return 0;
2628}
2629
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002630static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002631{
2632 /* FCS is enabled only in ERTM or streaming mode, if one or both
2633 * sides request it.
2634 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002635 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002636 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002637 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002638 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002639}
2640
Al Viro88219a02007-07-29 00:17:25 -07002641static 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 -07002642{
2643 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2644 u16 dcid, flags;
2645 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002646 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002648 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649
2650 dcid = __le16_to_cpu(req->dcid);
2651 flags = __le16_to_cpu(req->flags);
2652
2653 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2654
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002655 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002656 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 return -ENOENT;
2658
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002659 sk = chan->sk;
2660
David S. Miller033b1142011-07-21 13:38:42 -07002661 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002662 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002663
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002664 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2665 rej.scid = cpu_to_le16(chan->scid);
2666 rej.dcid = cpu_to_le16(chan->dcid);
2667
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002668 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2669 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002670 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002671 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002672
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002673 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002674 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002675 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002676 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002677 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002678 L2CAP_CONF_REJECT, flags), rsp);
2679 goto unlock;
2680 }
2681
2682 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002683 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2684 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685
2686 if (flags & 0x0001) {
2687 /* Incomplete config. Send empty response. */
2688 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002689 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002690 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 goto unlock;
2692 }
2693
2694 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002695 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002696 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002697 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002699 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002701 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002702 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002703
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002704 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002705 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002706
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002707 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002708 goto unlock;
2709
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002710 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002711 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002712
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002713 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002714
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002715 chan->next_tx_seq = 0;
2716 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002717 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002718 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002719 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002720
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002722 goto unlock;
2723 }
2724
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002725 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002726 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002727 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002728 l2cap_build_conf_req(chan, buf), buf);
2729 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 }
2731
2732unlock:
2733 bh_unlock_sock(sk);
2734 return 0;
2735}
2736
2737static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2738{
2739 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2740 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002741 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002743 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744
2745 scid = __le16_to_cpu(rsp->scid);
2746 flags = __le16_to_cpu(rsp->flags);
2747 result = __le16_to_cpu(rsp->result);
2748
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002749 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2750 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002752 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002753 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 return 0;
2755
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002756 sk = chan->sk;
2757
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 switch (result) {
2759 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002760 l2cap_conf_rfc_get(chan, rsp->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 break;
2762
2763 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002764 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002765 char req[64];
2766
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002767 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002768 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002769 goto done;
2770 }
2771
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002772 /* throw out any old stored conf requests */
2773 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002774 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2775 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002776 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002777 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002778 goto done;
2779 }
2780
2781 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2782 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002783 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002784 if (result != L2CAP_CONF_SUCCESS)
2785 goto done;
2786 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 }
2788
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002789 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002790 sk->sk_err = ECONNRESET;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002791 __set_chan_timer(chan, HZ * 5);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002792 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 goto done;
2794 }
2795
2796 if (flags & 0x01)
2797 goto done;
2798
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002799 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002801 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002802 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002803
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002804 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002805 chan->next_tx_seq = 0;
2806 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002807 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002808 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002809 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002810
Linus Torvalds1da177e2005-04-16 15:20:36 -07002811 l2cap_chan_ready(sk);
2812 }
2813
2814done:
2815 bh_unlock_sock(sk);
2816 return 0;
2817}
2818
2819static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2820{
2821 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2822 struct l2cap_disconn_rsp rsp;
2823 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002824 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 struct sock *sk;
2826
2827 scid = __le16_to_cpu(req->scid);
2828 dcid = __le16_to_cpu(req->dcid);
2829
2830 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2831
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002832 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002833 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 return 0;
2835
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002836 sk = chan->sk;
2837
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002838 rsp.dcid = cpu_to_le16(chan->scid);
2839 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2841
2842 sk->sk_shutdown = SHUTDOWN_MASK;
2843
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002844 /* don't delete l2cap channel if sk is owned by user */
2845 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002846 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002847 __clear_chan_timer(chan);
2848 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002849 bh_unlock_sock(sk);
2850 return 0;
2851 }
2852
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002853 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 bh_unlock_sock(sk);
2855
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002856 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 return 0;
2858}
2859
2860static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2861{
2862 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
2863 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002864 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 struct sock *sk;
2866
2867 scid = __le16_to_cpu(rsp->scid);
2868 dcid = __le16_to_cpu(rsp->dcid);
2869
2870 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
2871
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002872 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002873 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 return 0;
2875
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002876 sk = chan->sk;
2877
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002878 /* don't delete l2cap channel if sk is owned by user */
2879 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002880 l2cap_state_change(chan,BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002881 __clear_chan_timer(chan);
2882 __set_chan_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002883 bh_unlock_sock(sk);
2884 return 0;
2885 }
2886
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002887 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 bh_unlock_sock(sk);
2889
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002890 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 return 0;
2892}
2893
2894static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2895{
2896 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 u16 type;
2898
2899 type = __le16_to_cpu(req->type);
2900
2901 BT_DBG("type 0x%4.4x", type);
2902
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002903 if (type == L2CAP_IT_FEAT_MASK) {
2904 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07002905 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002906 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2907 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2908 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03002909 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002910 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
2911 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03002912 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002913 feat_mask |= L2CAP_FEAT_EXT_FLOW
2914 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03002915
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03002916 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002917 l2cap_send_cmd(conn, cmd->ident,
2918 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002919 } else if (type == L2CAP_IT_FIXED_CHAN) {
2920 u8 buf[12];
2921 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2922 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2923 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
2924 memcpy(buf + 4, l2cap_fixed_chan, 8);
2925 l2cap_send_cmd(conn, cmd->ident,
2926 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002927 } else {
2928 struct l2cap_info_rsp rsp;
2929 rsp.type = cpu_to_le16(type);
2930 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
2931 l2cap_send_cmd(conn, cmd->ident,
2932 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
2933 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934
2935 return 0;
2936}
2937
2938static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2939{
2940 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
2941 u16 type, result;
2942
2943 type = __le16_to_cpu(rsp->type);
2944 result = __le16_to_cpu(rsp->result);
2945
2946 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
2947
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02002948 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
2949 if (cmd->ident != conn->info_ident ||
2950 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
2951 return 0;
2952
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002953 del_timer(&conn->info_timer);
2954
Ville Tervoadb08ed2010-08-04 09:43:33 +03002955 if (result != L2CAP_IR_SUCCESS) {
2956 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2957 conn->info_ident = 0;
2958
2959 l2cap_conn_start(conn);
2960
2961 return 0;
2962 }
2963
Marcel Holtmann984947d2009-02-06 23:35:19 +01002964 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07002965 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002966
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002967 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002968 struct l2cap_info_req req;
2969 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2970
2971 conn->info_ident = l2cap_get_ident(conn);
2972
2973 l2cap_send_cmd(conn, conn->info_ident,
2974 L2CAP_INFO_REQ, sizeof(req), &req);
2975 } else {
2976 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2977 conn->info_ident = 0;
2978
2979 l2cap_conn_start(conn);
2980 }
2981 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01002982 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002983 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002984
2985 l2cap_conn_start(conn);
2986 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002987
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 return 0;
2989}
2990
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002991static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02002992 u16 to_multiplier)
2993{
2994 u16 max_latency;
2995
2996 if (min > max || min < 6 || max > 3200)
2997 return -EINVAL;
2998
2999 if (to_multiplier < 10 || to_multiplier > 3200)
3000 return -EINVAL;
3001
3002 if (max >= to_multiplier * 8)
3003 return -EINVAL;
3004
3005 max_latency = (to_multiplier * 8 / max) - 1;
3006 if (latency > 499 || latency > max_latency)
3007 return -EINVAL;
3008
3009 return 0;
3010}
3011
3012static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3013 struct l2cap_cmd_hdr *cmd, u8 *data)
3014{
3015 struct hci_conn *hcon = conn->hcon;
3016 struct l2cap_conn_param_update_req *req;
3017 struct l2cap_conn_param_update_rsp rsp;
3018 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003019 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003020
3021 if (!(hcon->link_mode & HCI_LM_MASTER))
3022 return -EINVAL;
3023
3024 cmd_len = __le16_to_cpu(cmd->len);
3025 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3026 return -EPROTO;
3027
3028 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003029 min = __le16_to_cpu(req->min);
3030 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003031 latency = __le16_to_cpu(req->latency);
3032 to_multiplier = __le16_to_cpu(req->to_multiplier);
3033
3034 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3035 min, max, latency, to_multiplier);
3036
3037 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003038
3039 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3040 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003041 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3042 else
3043 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3044
3045 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3046 sizeof(rsp), &rsp);
3047
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003048 if (!err)
3049 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3050
Claudio Takahaside731152011-02-11 19:28:55 -02003051 return 0;
3052}
3053
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003054static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3055 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3056{
3057 int err = 0;
3058
3059 switch (cmd->code) {
3060 case L2CAP_COMMAND_REJ:
3061 l2cap_command_rej(conn, cmd, data);
3062 break;
3063
3064 case L2CAP_CONN_REQ:
3065 err = l2cap_connect_req(conn, cmd, data);
3066 break;
3067
3068 case L2CAP_CONN_RSP:
3069 err = l2cap_connect_rsp(conn, cmd, data);
3070 break;
3071
3072 case L2CAP_CONF_REQ:
3073 err = l2cap_config_req(conn, cmd, cmd_len, data);
3074 break;
3075
3076 case L2CAP_CONF_RSP:
3077 err = l2cap_config_rsp(conn, cmd, data);
3078 break;
3079
3080 case L2CAP_DISCONN_REQ:
3081 err = l2cap_disconnect_req(conn, cmd, data);
3082 break;
3083
3084 case L2CAP_DISCONN_RSP:
3085 err = l2cap_disconnect_rsp(conn, cmd, data);
3086 break;
3087
3088 case L2CAP_ECHO_REQ:
3089 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3090 break;
3091
3092 case L2CAP_ECHO_RSP:
3093 break;
3094
3095 case L2CAP_INFO_REQ:
3096 err = l2cap_information_req(conn, cmd, data);
3097 break;
3098
3099 case L2CAP_INFO_RSP:
3100 err = l2cap_information_rsp(conn, cmd, data);
3101 break;
3102
3103 default:
3104 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3105 err = -EINVAL;
3106 break;
3107 }
3108
3109 return err;
3110}
3111
3112static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3113 struct l2cap_cmd_hdr *cmd, u8 *data)
3114{
3115 switch (cmd->code) {
3116 case L2CAP_COMMAND_REJ:
3117 return 0;
3118
3119 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003120 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003121
3122 case L2CAP_CONN_PARAM_UPDATE_RSP:
3123 return 0;
3124
3125 default:
3126 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3127 return -EINVAL;
3128 }
3129}
3130
3131static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3132 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133{
3134 u8 *data = skb->data;
3135 int len = skb->len;
3136 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003137 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003138
3139 l2cap_raw_recv(conn, skb);
3140
3141 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003142 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3144 data += L2CAP_CMD_HDR_SIZE;
3145 len -= L2CAP_CMD_HDR_SIZE;
3146
Al Viro88219a02007-07-29 00:17:25 -07003147 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003148
Al Viro88219a02007-07-29 00:17:25 -07003149 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 -07003150
Al Viro88219a02007-07-29 00:17:25 -07003151 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003152 BT_DBG("corrupted command");
3153 break;
3154 }
3155
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003156 if (conn->hcon->type == LE_LINK)
3157 err = l2cap_le_sig_cmd(conn, &cmd, data);
3158 else
3159 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
3161 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003162 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003163
3164 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165
3166 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003167 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3169 }
3170
Al Viro88219a02007-07-29 00:17:25 -07003171 data += cmd_len;
3172 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 }
3174
3175 kfree_skb(skb);
3176}
3177
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003178static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003179{
3180 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003181 int hdr_size;
3182
3183 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3184 hdr_size = L2CAP_EXT_HDR_SIZE;
3185 else
3186 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003187
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003188 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003189 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003190 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3191 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3192
3193 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003194 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003195 }
3196 return 0;
3197}
3198
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003199static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003200{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003201 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003202
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003203 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003204
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003205 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003206
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003207 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003208 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003209 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003210 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003211 }
3212
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003213 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003214 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003215
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003216 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003217
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003218 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003219 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003220 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003221 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003222 }
3223}
3224
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003225static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003226{
3227 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003228 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003229
3230 bt_cb(skb)->tx_seq = tx_seq;
3231 bt_cb(skb)->sar = sar;
3232
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003233 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003234 if (!next_skb) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003235 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003236 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003237 }
3238
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003239 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003240
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003241 do {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003242 if (bt_cb(next_skb)->tx_seq == tx_seq)
3243 return -EINVAL;
3244
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003245 next_tx_seq_offset = __seq_offset(chan,
3246 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003247
3248 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003249 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003250 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003251 }
3252
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003253 if (skb_queue_is_last(&chan->srej_q, next_skb))
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003254 break;
3255
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003256 } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003257
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003258 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003259
3260 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003261}
3262
Mat Martineau84084a32011-07-22 14:54:00 -07003263static void append_skb_frag(struct sk_buff *skb,
3264 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003265{
Mat Martineau84084a32011-07-22 14:54:00 -07003266 /* skb->len reflects data in skb as well as all fragments
3267 * skb->data_len reflects only data in fragments
3268 */
3269 if (!skb_has_frag_list(skb))
3270 skb_shinfo(skb)->frag_list = new_frag;
3271
3272 new_frag->next = NULL;
3273
3274 (*last_frag)->next = new_frag;
3275 *last_frag = new_frag;
3276
3277 skb->len += new_frag->len;
3278 skb->data_len += new_frag->len;
3279 skb->truesize += new_frag->truesize;
3280}
3281
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003282static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003283{
3284 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003285
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003286 switch (__get_ctrl_sar(chan, control)) {
3287 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003288 if (chan->sdu)
3289 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003290
Mat Martineau84084a32011-07-22 14:54:00 -07003291 err = chan->ops->recv(chan->data, skb);
3292 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003293
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003294 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003295 if (chan->sdu)
3296 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003297
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003298 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003299 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003300
Mat Martineau84084a32011-07-22 14:54:00 -07003301 if (chan->sdu_len > chan->imtu) {
3302 err = -EMSGSIZE;
3303 break;
3304 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003305
Mat Martineau84084a32011-07-22 14:54:00 -07003306 if (skb->len >= chan->sdu_len)
3307 break;
3308
3309 chan->sdu = skb;
3310 chan->sdu_last_frag = skb;
3311
3312 skb = NULL;
3313 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003314 break;
3315
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003316 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003317 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003318 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003319
Mat Martineau84084a32011-07-22 14:54:00 -07003320 append_skb_frag(chan->sdu, skb,
3321 &chan->sdu_last_frag);
3322 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003323
Mat Martineau84084a32011-07-22 14:54:00 -07003324 if (chan->sdu->len >= chan->sdu_len)
3325 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003326
Mat Martineau84084a32011-07-22 14:54:00 -07003327 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003328 break;
3329
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003330 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003331 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003332 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003333
Mat Martineau84084a32011-07-22 14:54:00 -07003334 append_skb_frag(chan->sdu, skb,
3335 &chan->sdu_last_frag);
3336 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003337
Mat Martineau84084a32011-07-22 14:54:00 -07003338 if (chan->sdu->len != chan->sdu_len)
3339 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003340
Mat Martineau84084a32011-07-22 14:54:00 -07003341 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003342
Mat Martineau84084a32011-07-22 14:54:00 -07003343 if (!err) {
3344 /* Reassembly complete */
3345 chan->sdu = NULL;
3346 chan->sdu_last_frag = NULL;
3347 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003348 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003349 break;
3350 }
3351
Mat Martineau84084a32011-07-22 14:54:00 -07003352 if (err) {
3353 kfree_skb(skb);
3354 kfree_skb(chan->sdu);
3355 chan->sdu = NULL;
3356 chan->sdu_last_frag = NULL;
3357 chan->sdu_len = 0;
3358 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003359
Mat Martineau84084a32011-07-22 14:54:00 -07003360 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003361}
3362
Mat Martineau26f880d2011-07-07 09:39:01 -07003363static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003364{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003365 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003366
Mat Martineau26f880d2011-07-07 09:39:01 -07003367 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003368
Mat Martineau26f880d2011-07-07 09:39:01 -07003369 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3370
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003371 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003372 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Mat Martineau26f880d2011-07-07 09:39:01 -07003373 l2cap_send_sframe(chan, control);
3374
3375 set_bit(CONN_RNR_SENT, &chan->conn_state);
3376
3377 __clear_ack_timer(chan);
3378}
3379
3380static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3381{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003382 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003383
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003384 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003385 goto done;
3386
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003387 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003388 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003389 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003390 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003391 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003392
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003393 __clear_retrans_timer(chan);
3394 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003395
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003396 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003397
3398done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003399 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3400 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003401
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003402 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003403}
3404
Mat Martineaue3281402011-07-07 09:39:02 -07003405void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003406{
Mat Martineaue3281402011-07-07 09:39:02 -07003407 if (chan->mode == L2CAP_MODE_ERTM) {
3408 if (busy)
3409 l2cap_ertm_enter_local_busy(chan);
3410 else
3411 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003412 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003413}
3414
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003415static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003416{
3417 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003418 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003419
Mat Martineaue3281402011-07-07 09:39:02 -07003420 while ((skb = skb_peek(&chan->srej_q)) &&
3421 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3422 int err;
3423
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003424 if (bt_cb(skb)->tx_seq != tx_seq)
3425 break;
3426
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003427 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003428 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003429 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003430
3431 if (err < 0) {
3432 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3433 break;
3434 }
3435
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003436 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3437 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003438 }
3439}
3440
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003441static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003442{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003443 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003444 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003445
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003446 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003447 if (l->tx_seq == tx_seq) {
3448 list_del(&l->list);
3449 kfree(l);
3450 return;
3451 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003452 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003453 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003454 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003455 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003456 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003457 }
3458}
3459
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003460static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003461{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003462 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003463 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003464
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003465 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003466 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003467 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003468 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003469
3470 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003471 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003472
3473 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3474
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003475 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003476 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003477
3478 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003479}
3480
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003481static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003482{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003483 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003484 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003485 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003486 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003487 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003488 int err = 0;
3489
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003490 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003491 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003492
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003493 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003494 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003495 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003496 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003497 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003498 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003499 }
3500
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003501 chan->expected_ack_seq = req_seq;
3502 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003503
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003504 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003505
3506 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003507 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003508 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003509 goto drop;
3510 }
3511
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003512 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003513 goto drop;
3514
Mat Martineau02f1b642011-06-29 14:35:19 -07003515 if (tx_seq == chan->expected_tx_seq)
3516 goto expected;
3517
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003518 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003519 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003520
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003521 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003522 struct srej_list, list);
3523 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003524 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003525 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003526
3527 list_del(&first->list);
3528 kfree(first);
3529
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003530 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003531 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003532 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003533 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003534 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003535 }
3536 } else {
3537 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003538
3539 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003540 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003541 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003542
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003543 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003544 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003545 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003546 return 0;
3547 }
3548 }
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003549 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003550 }
3551 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003552 expected_tx_seq_offset = __seq_offset(chan,
3553 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003554
3555 /* duplicated tx_seq */
3556 if (tx_seq_offset < expected_tx_seq_offset)
3557 goto drop;
3558
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003559 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003560
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003561 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003562
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003563 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003564 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003565
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003566 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003567 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003568
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003569 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003570
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003571 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003572
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003573 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003574 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003575 return 0;
3576
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003577expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003578 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003579
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003580 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003581 bt_cb(skb)->tx_seq = tx_seq;
3582 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003583 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003584 return 0;
3585 }
3586
Mat Martineau84084a32011-07-22 14:54:00 -07003587 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003588 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
3589
Mat Martineaue3281402011-07-07 09:39:02 -07003590 if (err < 0) {
3591 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3592 return err;
3593 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003594
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003595 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003596 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003597 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003598 }
3599
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003600 __set_ack_timer(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003601
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003602 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3603 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003604 l2cap_send_ack(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003605
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003606 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003607
3608drop:
3609 kfree_skb(skb);
3610 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003611}
3612
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003613static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003614{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003615 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003616 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003617
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003618 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003619 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003620
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003621 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003622 set_bit(CONN_SEND_FBIT, &chan->conn_state);
3623 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
3624 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003625 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003626 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003627
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003628 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003629 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003630 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003631 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003632 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003633
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003634 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003635 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003636
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003637 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003638 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003639
3640 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003641 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003642 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003643 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003644
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003645 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
3646 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003647 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003648 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003649 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003650 }
3651}
3652
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003653static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003654{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003655 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003656
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003657 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003658
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003659 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003660
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003661 chan->expected_ack_seq = tx_seq;
3662 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003663
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003664 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003665 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003666 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003667 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003668 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003669
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003670 if (test_bit(CONN_WAIT_F, &chan->conn_state))
3671 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003672 }
3673}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003674static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003675{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003676 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003677
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003678 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003679
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003680 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003681
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003682 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003683 chan->expected_ack_seq = tx_seq;
3684 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003685
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003686 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003687 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003688
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003689 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003690
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003691 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003692 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003693 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003694 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003695 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003696 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003697 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003698 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003699 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003700 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003701 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003702 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003703 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003704 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003705 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003706 }
3707 }
3708}
3709
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003710static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003711{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003712 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003713
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003714 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003715
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003716 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003717 chan->expected_ack_seq = tx_seq;
3718 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003719
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003720 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003721 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003722
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003723 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003724 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003725 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003726 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003727 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003728 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003729
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003730 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003731 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003732 } else {
3733 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
3734 l2cap_send_sframe(chan, rx_control);
3735 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003736}
3737
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003738static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003739{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003740 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003741
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003742 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003743 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003744 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003745 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003746 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003747 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003748 }
3749
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003750 switch (__get_ctrl_super(chan, rx_control)) {
3751 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003752 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003753 break;
3754
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003755 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003756 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003757 break;
3758
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003759 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003760 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003761 break;
3762
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003763 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003764 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003765 break;
3766 }
3767
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03003768 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003769 return 0;
3770}
3771
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003772static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
3773{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003774 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003775 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003776 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003777 int len, next_tx_seq_offset, req_seq_offset;
3778
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003779 control = __get_control(chan, skb->data);
3780 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003781 len = skb->len;
3782
3783 /*
3784 * We can just drop the corrupted I-frame here.
3785 * Receiver will miss it and start proper recovery
3786 * procedures and ask retransmission.
3787 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003788 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003789 goto drop;
3790
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03003791 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003792 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003793
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003794 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003795 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003796
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003797 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003798 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003799 goto drop;
3800 }
3801
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003802 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003803
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003804 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
3805
3806 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
3807 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003808
3809 /* check for invalid req-seq */
3810 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003811 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003812 goto drop;
3813 }
3814
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03003815 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003816 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003817 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003818 goto drop;
3819 }
3820
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003821 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003822 } else {
3823 if (len != 0) {
3824 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003825 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003826 goto drop;
3827 }
3828
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003829 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003830 }
3831
3832 return 0;
3833
3834drop:
3835 kfree_skb(skb);
3836 return 0;
3837}
3838
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
3840{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003841 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07003842 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003843 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003844 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003845 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003847 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003848 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849 BT_DBG("unknown cid 0x%4.4x", cid);
3850 goto drop;
3851 }
3852
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003853 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003854
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003855 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003857 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003858 goto drop;
3859
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003860 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003861 case L2CAP_MODE_BASIC:
3862 /* If socket recv buffers overflows we drop data here
3863 * which is *bad* because L2CAP has to be reliable.
3864 * But we don't have any other choice. L2CAP doesn't
3865 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003867 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003868 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003870 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003871 goto done;
3872 break;
3873
3874 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003875 if (!sock_owned_by_user(sk)) {
3876 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003877 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003878 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003879 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003880 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003881
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02003882 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003883
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003884 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003885 control = __get_control(chan, skb->data);
3886 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003887 len = skb->len;
3888
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003889 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03003890 goto drop;
3891
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003892 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003893 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003894
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003895 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003896 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003897
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03003898 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003899 goto drop;
3900
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003901 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003902
Mat Martineau84084a32011-07-22 14:54:00 -07003903 if (chan->expected_tx_seq != tx_seq) {
3904 /* Frame(s) missing - must discard partial SDU */
3905 kfree_skb(chan->sdu);
3906 chan->sdu = NULL;
3907 chan->sdu_last_frag = NULL;
3908 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003909
Mat Martineau84084a32011-07-22 14:54:00 -07003910 /* TODO: Notify userland of missing data */
3911 }
3912
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003913 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07003914
3915 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
3916 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003917
3918 goto done;
3919
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003920 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003921 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003922 break;
3923 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924
3925drop:
3926 kfree_skb(skb);
3927
3928done:
Marcel Holtmann01394182006-07-03 10:02:46 +02003929 if (sk)
3930 bh_unlock_sock(sk);
3931
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 return 0;
3933}
3934
Al Viro8e036fc2007-07-29 00:16:36 -07003935static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003937 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003938 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003940 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
3941 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942 goto drop;
3943
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003944 sk = chan->sk;
3945
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00003946 bh_lock_sock(sk);
3947
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 BT_DBG("sk %p, len %d", sk, skb->len);
3949
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003950 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951 goto drop;
3952
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03003953 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 goto drop;
3955
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003956 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 goto done;
3958
3959drop:
3960 kfree_skb(skb);
3961
3962done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03003963 if (sk)
3964 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 return 0;
3966}
3967
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003968static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
3969{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003970 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003971 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003972
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003973 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
3974 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003975 goto drop;
3976
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003977 sk = chan->sk;
3978
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003979 bh_lock_sock(sk);
3980
3981 BT_DBG("sk %p, len %d", sk, skb->len);
3982
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003983 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003984 goto drop;
3985
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03003986 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003987 goto drop;
3988
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003989 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003990 goto done;
3991
3992drop:
3993 kfree_skb(skb);
3994
3995done:
3996 if (sk)
3997 bh_unlock_sock(sk);
3998 return 0;
3999}
4000
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4002{
4003 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004004 u16 cid, len;
4005 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006
4007 skb_pull(skb, L2CAP_HDR_SIZE);
4008 cid = __le16_to_cpu(lh->cid);
4009 len = __le16_to_cpu(lh->len);
4010
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004011 if (len != skb->len) {
4012 kfree_skb(skb);
4013 return;
4014 }
4015
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4017
4018 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004019 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004020 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 l2cap_sig_channel(conn, skb);
4022 break;
4023
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004024 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004025 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 skb_pull(skb, 2);
4027 l2cap_conless_channel(conn, psm, skb);
4028 break;
4029
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004030 case L2CAP_CID_LE_DATA:
4031 l2cap_att_channel(conn, cid, skb);
4032 break;
4033
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004034 case L2CAP_CID_SMP:
4035 if (smp_sig_channel(conn, skb))
4036 l2cap_conn_del(conn->hcon, EACCES);
4037 break;
4038
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039 default:
4040 l2cap_data_channel(conn, cid, skb);
4041 break;
4042 }
4043}
4044
4045/* ---- L2CAP interface with lower layer (HCI) ---- */
4046
4047static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4048{
4049 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004050 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004051
4052 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004053 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054
4055 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4056
4057 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004058 read_lock(&chan_list_lock);
4059 list_for_each_entry(c, &chan_list, global_l) {
4060 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004061
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004062 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063 continue;
4064
4065 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004066 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004067 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004068 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004070 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4071 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004072 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004073 lm2 |= HCI_LM_MASTER;
4074 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004076 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077
4078 return exact ? lm1 : lm2;
4079}
4080
4081static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4082{
Marcel Holtmann01394182006-07-03 10:02:46 +02004083 struct l2cap_conn *conn;
4084
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4086
Ville Tervoacd7d372011-02-10 22:38:49 -03004087 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004088 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089
4090 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091 conn = l2cap_conn_add(hcon, status);
4092 if (conn)
4093 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004094 } else
Joe Perchese1750722011-06-29 18:18:29 -07004095 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096
4097 return 0;
4098}
4099
Marcel Holtmann2950f212009-02-12 14:02:50 +01004100static int l2cap_disconn_ind(struct hci_conn *hcon)
4101{
4102 struct l2cap_conn *conn = hcon->l2cap_data;
4103
4104 BT_DBG("hcon %p", hcon);
4105
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004106 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004107 return 0x13;
4108
4109 return conn->disc_reason;
4110}
4111
4112static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113{
4114 BT_DBG("hcon %p reason %d", hcon, reason);
4115
Ville Tervoacd7d372011-02-10 22:38:49 -03004116 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004117 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118
Joe Perchese1750722011-06-29 18:18:29 -07004119 l2cap_conn_del(hcon, bt_to_errno(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004120
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121 return 0;
4122}
4123
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004124static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004125{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004126 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004127 return;
4128
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004129 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004130 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004131 __clear_chan_timer(chan);
4132 __set_chan_timer(chan, HZ * 5);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004133 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004134 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004135 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004136 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004137 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004138 }
4139}
4140
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004141static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004143 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004144 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145
Marcel Holtmann01394182006-07-03 10:02:46 +02004146 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004148
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149 BT_DBG("conn %p", conn);
4150
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004151 if (hcon->type == LE_LINK) {
4152 smp_distribute_keys(conn, 0);
4153 del_timer(&conn->security_timer);
4154 }
4155
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004156 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004157
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004158 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004159 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004160
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161 bh_lock_sock(sk);
4162
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004163 BT_DBG("chan->scid %d", chan->scid);
4164
4165 if (chan->scid == L2CAP_CID_LE_DATA) {
4166 if (!status && encrypt) {
4167 chan->sec_level = hcon->sec_level;
4168 l2cap_chan_ready(sk);
4169 }
4170
4171 bh_unlock_sock(sk);
4172 continue;
4173 }
4174
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004175 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004176 bh_unlock_sock(sk);
4177 continue;
4178 }
4179
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004180 if (!status && (chan->state == BT_CONNECTED ||
4181 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004182 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004183 bh_unlock_sock(sk);
4184 continue;
4185 }
4186
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004187 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004188 if (!status) {
4189 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004190 req.scid = cpu_to_le16(chan->scid);
4191 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004192
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004193 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004194 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004195
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004196 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004197 L2CAP_CONN_REQ, sizeof(req), &req);
4198 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004199 __clear_chan_timer(chan);
4200 __set_chan_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004201 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004202 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004203 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004204 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004205
4206 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004207 if (bt_sk(sk)->defer_setup) {
4208 struct sock *parent = bt_sk(sk)->parent;
4209 res = L2CAP_CR_PEND;
4210 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004211 if (parent)
4212 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004213 } else {
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004214 l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004215 res = L2CAP_CR_SUCCESS;
4216 stat = L2CAP_CS_NO_INFO;
4217 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004218 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004219 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004220 __set_chan_timer(chan, HZ / 10);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004221 res = L2CAP_CR_SEC_BLOCK;
4222 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004223 }
4224
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004225 rsp.scid = cpu_to_le16(chan->dcid);
4226 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004227 rsp.result = cpu_to_le16(res);
4228 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004229 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4230 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004231 }
4232
Linus Torvalds1da177e2005-04-16 15:20:36 -07004233 bh_unlock_sock(sk);
4234 }
4235
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004236 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004237
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 return 0;
4239}
4240
4241static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4242{
4243 struct l2cap_conn *conn = hcon->l2cap_data;
4244
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004245 if (!conn)
4246 conn = l2cap_conn_add(hcon, 0);
4247
4248 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 goto drop;
4250
4251 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4252
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004253 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004255 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004256 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257 int len;
4258
4259 if (conn->rx_len) {
4260 BT_ERR("Unexpected start frame (len %d)", skb->len);
4261 kfree_skb(conn->rx_skb);
4262 conn->rx_skb = NULL;
4263 conn->rx_len = 0;
4264 l2cap_conn_unreliable(conn, ECOMM);
4265 }
4266
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004267 /* Start fragment always begin with Basic L2CAP header */
4268 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 BT_ERR("Frame is too short (len %d)", skb->len);
4270 l2cap_conn_unreliable(conn, ECOMM);
4271 goto drop;
4272 }
4273
4274 hdr = (struct l2cap_hdr *) skb->data;
4275 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004276 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277
4278 if (len == skb->len) {
4279 /* Complete frame received */
4280 l2cap_recv_frame(conn, skb);
4281 return 0;
4282 }
4283
4284 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4285
4286 if (skb->len > len) {
4287 BT_ERR("Frame is too long (len %d, expected len %d)",
4288 skb->len, len);
4289 l2cap_conn_unreliable(conn, ECOMM);
4290 goto drop;
4291 }
4292
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004293 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004294
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004295 if (chan && chan->sk) {
4296 struct sock *sk = chan->sk;
4297
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004298 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004299 BT_ERR("Frame exceeding recv MTU (len %d, "
4300 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004301 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004302 bh_unlock_sock(sk);
4303 l2cap_conn_unreliable(conn, ECOMM);
4304 goto drop;
4305 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004306 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004307 }
4308
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004310 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4311 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 goto drop;
4313
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004314 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004315 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004316 conn->rx_len = len - skb->len;
4317 } else {
4318 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4319
4320 if (!conn->rx_len) {
4321 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4322 l2cap_conn_unreliable(conn, ECOMM);
4323 goto drop;
4324 }
4325
4326 if (skb->len > conn->rx_len) {
4327 BT_ERR("Fragment is too long (len %d, expected %d)",
4328 skb->len, conn->rx_len);
4329 kfree_skb(conn->rx_skb);
4330 conn->rx_skb = NULL;
4331 conn->rx_len = 0;
4332 l2cap_conn_unreliable(conn, ECOMM);
4333 goto drop;
4334 }
4335
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004336 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004337 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 conn->rx_len -= skb->len;
4339
4340 if (!conn->rx_len) {
4341 /* Complete frame received */
4342 l2cap_recv_frame(conn, conn->rx_skb);
4343 conn->rx_skb = NULL;
4344 }
4345 }
4346
4347drop:
4348 kfree_skb(skb);
4349 return 0;
4350}
4351
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004352static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004354 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004356 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004358 list_for_each_entry(c, &chan_list, global_l) {
4359 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004361 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 +01004362 batostr(&bt_sk(sk)->src),
4363 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004364 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004365 c->scid, c->dcid, c->imtu, c->omtu,
4366 c->sec_level, c->mode);
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004367}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004369 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004370
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004371 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004372}
4373
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004374static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4375{
4376 return single_open(file, l2cap_debugfs_show, inode->i_private);
4377}
4378
4379static const struct file_operations l2cap_debugfs_fops = {
4380 .open = l2cap_debugfs_open,
4381 .read = seq_read,
4382 .llseek = seq_lseek,
4383 .release = single_release,
4384};
4385
4386static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004387
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388static struct hci_proto l2cap_hci_proto = {
4389 .name = "L2CAP",
4390 .id = HCI_PROTO_L2CAP,
4391 .connect_ind = l2cap_connect_ind,
4392 .connect_cfm = l2cap_connect_cfm,
4393 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004394 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004395 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 .recv_acldata = l2cap_recv_acldata
4397};
4398
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004399int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400{
4401 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004402
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004403 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 if (err < 0)
4405 return err;
4406
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 err = hci_register_proto(&l2cap_hci_proto);
4408 if (err < 0) {
4409 BT_ERR("L2CAP protocol registration failed");
4410 bt_sock_unregister(BTPROTO_L2CAP);
4411 goto error;
4412 }
4413
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004414 if (bt_debugfs) {
4415 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4416 bt_debugfs, NULL, &l2cap_debugfs_fops);
4417 if (!l2cap_debugfs)
4418 BT_ERR("Failed to create L2CAP debug file");
4419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004420
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 return 0;
4422
4423error:
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004424 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004425 return err;
4426}
4427
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004428void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004430 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004431
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4433 BT_ERR("L2CAP protocol unregistration failed");
4434
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004435 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436}
4437
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004438module_param(disable_ertm, bool, 0644);
4439MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03004440
4441module_param(enable_hs, bool, 0644);
4442MODULE_PARM_DESC(enable_hs, "Enable High Speed");