blob: 32f830acee68ea3aaff5f15301e47af84d2e46b7 [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. Padovanaf05b302009-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>
57
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020058int disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020059
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070060static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Marcel Holtmanne1027a72009-02-09 09:18:02 +010061static u8 l2cap_fixed_chan[8] = { 0x02, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Gustavo F. Padovan1890d362010-05-01 16:15:44 -030063static struct workqueue_struct *_busy_wq;
64
Gustavo F. Padovan23691d72011-04-27 18:26:32 -030065LIST_HEAD(chan_list);
66DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Gustavo F. Padovan1890d362010-05-01 16:15:44 -030068static void l2cap_busy_work(struct work_struct *work);
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
71 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030072static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030074static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
75
Marcel Holtmann01394182006-07-03 10:02:46 +020076/* ---- L2CAP channels ---- */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030077static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020078{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030079 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030080
81 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030082 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030083 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020084 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030085 return NULL;
86
Marcel Holtmann01394182006-07-03 10:02:46 +020087}
88
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030089static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020090{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030091 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030092
93 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030094 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030095 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020096 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030097 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020098}
99
100/* Find channel with given SCID.
101 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300102static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200103{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300104 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300105
106 read_lock(&conn->chan_lock);
107 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300108 if (c)
109 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300110 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300111 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200112}
113
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300114static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200115{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300116 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300117
118 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300119 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300120 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200121 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300122 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200123}
124
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300125static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200126{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300127 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300128
129 read_lock(&conn->chan_lock);
130 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300131 if (c)
132 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300133 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300134 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200135}
136
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300137static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300138{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300139 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300140
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300141 list_for_each_entry(c, &chan_list, global_l) {
142 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300143 goto found;
144 }
145
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300146 c = NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300147found:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300148 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300149}
150
151int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
152{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300153 int err;
154
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300155 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300156
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300157 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300158 err = -EADDRINUSE;
159 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300160 }
161
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300162 if (psm) {
163 chan->psm = psm;
164 chan->sport = psm;
165 err = 0;
166 } else {
167 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300168
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300169 err = -EINVAL;
170 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300171 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300172 chan->psm = cpu_to_le16(p);
173 chan->sport = cpu_to_le16(p);
174 err = 0;
175 break;
176 }
177 }
178
179done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300180 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300181 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300182}
183
184int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
185{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300186 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300187
188 chan->scid = scid;
189
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300190 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300191
192 return 0;
193}
194
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300195static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200196{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300197 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200198
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300199 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300200 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200201 return cid;
202 }
203
204 return 0;
205}
206
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300207struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200208{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300209 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200210
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300211 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
212 if (!chan)
213 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200214
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300215 chan->sk = sk;
216
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300217 write_lock_bh(&chan_list_lock);
218 list_add(&chan->global_l, &chan_list);
219 write_unlock_bh(&chan_list_lock);
220
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300221 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200222}
223
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300224void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300225{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300226 write_lock_bh(&chan_list_lock);
227 list_del(&chan->global_l);
228 write_unlock_bh(&chan_list_lock);
229
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300230 kfree(chan);
231}
232
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300233static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200234{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300235 struct sock *sk = chan->sk;
Marcel Holtmann01394182006-07-03 10:02:46 +0200236
Gustavo F. Padovanaf05b302009-04-20 01:31:08 -0300237 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300238 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200239
Marcel Holtmann2950f212009-02-12 14:02:50 +0100240 conn->disc_reason = 0x13;
241
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300242 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200243
Gustavo F. Padovanbd3c9e22010-05-01 16:15:42 -0300244 if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) {
Ville Tervob62f3282011-02-10 22:38:50 -0300245 if (conn->hcon->type == LE_LINK) {
246 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300247 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300248 chan->scid = L2CAP_CID_LE_DATA;
249 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300250 } else {
251 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300252 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300253 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300254 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200255 } else if (sk->sk_type == SOCK_DGRAM) {
256 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300257 chan->scid = L2CAP_CID_CONN_LESS;
258 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300259 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200260 } else {
261 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300262 chan->scid = L2CAP_CID_SIGNALING;
263 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300264 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200265 }
266
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300267 sock_hold(sk);
268
269 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200270}
271
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900272/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200273 * Must be called on the locked socket. */
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300274void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200275{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300276 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300277 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200278 struct sock *parent = bt_sk(sk)->parent;
279
280 l2cap_sock_clear_timer(sk);
281
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300282 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200283
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900284 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300285 /* Delete from channel list */
286 write_lock_bh(&conn->chan_lock);
287 list_del(&chan->list);
288 write_unlock_bh(&conn->chan_lock);
289 __sock_put(sk);
290
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300291 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200292 hci_conn_put(conn->hcon);
293 }
294
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200295 sk->sk_state = BT_CLOSED;
Marcel Holtmann01394182006-07-03 10:02:46 +0200296 sock_set_flag(sk, SOCK_ZAPPED);
297
298 if (err)
299 sk->sk_err = err;
300
301 if (parent) {
302 bt_accept_unlink(sk);
303 parent->sk_data_ready(parent, 0);
304 } else
305 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300306
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300307 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE &&
308 chan->conf_state & L2CAP_CONF_INPUT_DONE))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300309 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300310
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300311 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300312
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300313 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300314 struct srej_list *l, *tmp;
315
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300316 del_timer(&chan->retrans_timer);
317 del_timer(&chan->monitor_timer);
318 del_timer(&chan->ack_timer);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300319
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300320 skb_queue_purge(&chan->srej_q);
321 skb_queue_purge(&chan->busy_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300322
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300323 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300324 list_del(&l->list);
325 kfree(l);
326 }
327 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200328}
329
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300330static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530331{
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300332 struct sock *sk = chan->sk;
333
Johan Hedberg8556edd32011-01-19 12:06:50 +0530334 if (sk->sk_type == SOCK_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300335 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530336 case BT_SECURITY_HIGH:
337 return HCI_AT_DEDICATED_BONDING_MITM;
338 case BT_SECURITY_MEDIUM:
339 return HCI_AT_DEDICATED_BONDING;
340 default:
341 return HCI_AT_NO_BONDING;
342 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300343 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300344 if (chan->sec_level == BT_SECURITY_LOW)
345 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530346
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300347 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530348 return HCI_AT_NO_BONDING_MITM;
349 else
350 return HCI_AT_NO_BONDING;
351 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300352 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530353 case BT_SECURITY_HIGH:
354 return HCI_AT_GENERAL_BONDING_MITM;
355 case BT_SECURITY_MEDIUM:
356 return HCI_AT_GENERAL_BONDING;
357 default:
358 return HCI_AT_NO_BONDING;
359 }
360 }
361}
362
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200363/* Service level security */
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300364static inline int l2cap_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200365{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300366 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100367 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200368
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300369 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100370
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300371 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200372}
373
Gustavo F. Padovan68983252011-02-04 03:02:31 -0200374u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200375{
376 u8 id;
377
378 /* Get next available identificator.
379 * 1 - 128 are used by kernel.
380 * 129 - 199 are reserved.
381 * 200 - 254 are used by utilities like l2ping, etc.
382 */
383
384 spin_lock_bh(&conn->lock);
385
386 if (++conn->tx_ident > 128)
387 conn->tx_ident = 1;
388
389 id = conn->tx_ident;
390
391 spin_unlock_bh(&conn->lock);
392
393 return id;
394}
395
Gustavo F. Padovan68983252011-02-04 03:02:31 -0200396void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200397{
398 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200399 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200400
401 BT_DBG("code 0x%2.2x", code);
402
403 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300404 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200405
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200406 if (lmp_no_flush_capable(conn->hcon->hdev))
407 flags = ACL_START_NO_FLUSH;
408 else
409 flags = ACL_START;
410
411 hci_send_acl(conn->hcon, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200412}
413
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300414static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300415{
416 struct sk_buff *skb;
417 struct l2cap_hdr *lh;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300418 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300419 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300420 struct sock *sk = (struct sock *)pi;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300421 int count, hlen = L2CAP_HDR_SIZE + 2;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200422 u8 flags;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300423
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300424 if (sk->sk_state != BT_CONNECTED)
425 return;
426
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300427 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300428 hlen += 2;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300429
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300430 BT_DBG("chan %p, control 0x%2.2x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300431
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300432 count = min_t(unsigned int, conn->mtu, hlen);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300433 control |= L2CAP_CTRL_FRAME_TYPE;
434
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300435 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300436 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300437 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300438 }
439
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300440 if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300441 control |= L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300442 chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300443 }
444
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300445 skb = bt_skb_alloc(count, GFP_ATOMIC);
446 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300447 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300448
449 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300450 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300451 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300452 put_unaligned_le16(control, skb_put(skb, 2));
453
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300454 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300455 u16 fcs = crc16(0, (u8 *)lh, count - 2);
456 put_unaligned_le16(fcs, skb_put(skb, 2));
457 }
458
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200459 if (lmp_no_flush_capable(conn->hcon->hdev))
460 flags = ACL_START_NO_FLUSH;
461 else
462 flags = ACL_START;
463
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300464 hci_send_acl(chan->conn->hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300465}
466
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300467static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300468{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300469 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300470 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300471 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300472 } else
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300473 control |= L2CAP_SUPER_RCV_READY;
474
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -0300475 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300476
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300477 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300478}
479
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300480static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300481{
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300482 return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300483}
484
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300485static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200486{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300487 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200488
489 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100490 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
491 return;
492
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300493 if (l2cap_check_security(chan) &&
494 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200495 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300496 req.scid = cpu_to_le16(chan->scid);
497 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200498
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300499 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300500 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200501
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300502 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
503 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200504 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200505 } else {
506 struct l2cap_info_req req;
507 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
508
509 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
510 conn->info_ident = l2cap_get_ident(conn);
511
512 mod_timer(&conn->info_timer, jiffies +
513 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
514
515 l2cap_send_cmd(conn, conn->info_ident,
516 L2CAP_INFO_REQ, sizeof(req), &req);
517 }
518}
519
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300520static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
521{
522 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300523 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300524 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
525
526 switch (mode) {
527 case L2CAP_MODE_ERTM:
528 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
529 case L2CAP_MODE_STREAMING:
530 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
531 default:
532 return 0x00;
533 }
534}
535
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300536void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300537{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300538 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300539 struct l2cap_disconn_req req;
540
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300541 if (!conn)
542 return;
543
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300544 sk = chan->sk;
545
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300546 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300547 del_timer(&chan->retrans_timer);
548 del_timer(&chan->monitor_timer);
549 del_timer(&chan->ack_timer);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300550 }
551
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300552 req.dcid = cpu_to_le16(chan->dcid);
553 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300554 l2cap_send_cmd(conn, l2cap_get_ident(conn),
555 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300556
557 sk->sk_state = BT_DISCONN;
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300558 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300559}
560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200562static void l2cap_conn_start(struct l2cap_conn *conn)
563{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300564 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200565
566 BT_DBG("conn %p", conn);
567
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300568 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200569
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300570 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300571 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300572
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200573 bh_lock_sock(sk);
574
Gustavo F. Padovanbd3c9e22010-05-01 16:15:42 -0300575 if (sk->sk_type != SOCK_SEQPACKET &&
576 sk->sk_type != SOCK_STREAM) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200577 bh_unlock_sock(sk);
578 continue;
579 }
580
581 if (sk->sk_state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300582 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300583
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300584 if (!l2cap_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300585 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300586 bh_unlock_sock(sk);
587 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200588 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300589
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300590 if (!l2cap_mode_supported(chan->mode,
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300591 conn->feat_mask)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300592 && chan->conf_state &
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300593 L2CAP_CONF_STATE2_DEVICE) {
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300594 /* __l2cap_sock_close() calls list_del(chan)
595 * so release the lock */
596 read_unlock_bh(&conn->chan_lock);
597 __l2cap_sock_close(sk, ECONNRESET);
598 read_lock_bh(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300599 bh_unlock_sock(sk);
600 continue;
601 }
602
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300603 req.scid = cpu_to_le16(chan->scid);
604 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300605
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300606 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300607 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300608
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300609 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
610 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300611
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200612 } else if (sk->sk_state == BT_CONNECT2) {
613 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300614 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300615 rsp.scid = cpu_to_le16(chan->dcid);
616 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200617
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300618 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100619 if (bt_sk(sk)->defer_setup) {
620 struct sock *parent = bt_sk(sk)->parent;
621 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
622 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Nick Pellyf86e4b02010-04-08 16:23:32 -0700623 if (parent)
624 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100625
626 } else {
627 sk->sk_state = BT_CONFIG;
628 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
629 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
630 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200631 } else {
632 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
633 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
634 }
635
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300636 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
637 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300638
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300639 if (chan->conf_state & L2CAP_CONF_REQ_SENT ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300640 rsp.result != L2CAP_CR_SUCCESS) {
641 bh_unlock_sock(sk);
642 continue;
643 }
644
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300645 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300646 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300647 l2cap_build_conf_req(chan, buf), buf);
648 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200649 }
650
651 bh_unlock_sock(sk);
652 }
653
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300654 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200655}
656
Ville Tervob62f3282011-02-10 22:38:50 -0300657/* Find socket with cid and source bdaddr.
658 * Returns closest match, locked.
659 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300660static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300661{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300662 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300663
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300664 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300665
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300666 list_for_each_entry(c, &chan_list, global_l) {
667 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300668
Ville Tervob62f3282011-02-10 22:38:50 -0300669 if (state && sk->sk_state != state)
670 continue;
671
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300672 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300673 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300674 if (!bacmp(&bt_sk(sk)->src, src)) {
675 read_unlock(&chan_list_lock);
676 return c;
677 }
Ville Tervob62f3282011-02-10 22:38:50 -0300678
679 /* Closest match */
680 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300681 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300682 }
683 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300684
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300685 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300686
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300687 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300688}
689
690static void l2cap_le_conn_ready(struct l2cap_conn *conn)
691{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300692 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300693 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300694
695 BT_DBG("");
696
697 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300698 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300699 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300700 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300701 return;
702
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300703 parent = pchan->sk;
704
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300705 bh_lock_sock(parent);
706
Ville Tervob62f3282011-02-10 22:38:50 -0300707 /* Check for backlog size */
708 if (sk_acceptq_is_full(parent)) {
709 BT_DBG("backlog full %d", parent->sk_ack_backlog);
710 goto clean;
711 }
712
713 sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
714 if (!sk)
715 goto clean;
716
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300717 chan = l2cap_chan_create(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300718 if (!chan) {
719 l2cap_sock_kill(sk);
720 goto clean;
721 }
722
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300723 l2cap_pi(sk)->chan = chan;
724
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300725 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300726
727 hci_conn_hold(conn->hcon);
728
729 l2cap_sock_init(sk, parent);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300730
Ville Tervob62f3282011-02-10 22:38:50 -0300731 bacpy(&bt_sk(sk)->src, conn->src);
732 bacpy(&bt_sk(sk)->dst, conn->dst);
733
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300734 bt_accept_enqueue(parent, sk);
735
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300736 __l2cap_chan_add(conn, chan);
737
Ville Tervob62f3282011-02-10 22:38:50 -0300738 l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
739
740 sk->sk_state = BT_CONNECTED;
741 parent->sk_data_ready(parent, 0);
742
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300743 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300744
745clean:
746 bh_unlock_sock(parent);
747}
748
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200749static void l2cap_conn_ready(struct l2cap_conn *conn)
750{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300751 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200752
753 BT_DBG("conn %p", conn);
754
Ville Tervob62f3282011-02-10 22:38:50 -0300755 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
756 l2cap_le_conn_ready(conn);
757
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300758 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200759
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300760 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300761 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300762
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200763 bh_lock_sock(sk);
764
Ville Tervoacd7d372011-02-10 22:38:49 -0300765 if (conn->hcon->type == LE_LINK) {
766 l2cap_sock_clear_timer(sk);
767 sk->sk_state = BT_CONNECTED;
768 sk->sk_state_change(sk);
769 }
770
Gustavo F. Padovanbd3c9e22010-05-01 16:15:42 -0300771 if (sk->sk_type != SOCK_SEQPACKET &&
772 sk->sk_type != SOCK_STREAM) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200773 l2cap_sock_clear_timer(sk);
774 sk->sk_state = BT_CONNECTED;
775 sk->sk_state_change(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200776 } else if (sk->sk_state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300777 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200778
779 bh_unlock_sock(sk);
780 }
781
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300782 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200783}
784
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200785/* Notify sockets that we cannot guaranty reliability anymore */
786static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
787{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300788 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200789
790 BT_DBG("conn %p", conn);
791
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300792 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200793
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300794 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300795 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300796
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300797 if (chan->force_reliable)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200798 sk->sk_err = err;
799 }
800
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300801 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200802}
803
804static void l2cap_info_timeout(unsigned long arg)
805{
806 struct l2cap_conn *conn = (void *) arg;
807
Marcel Holtmann984947d2009-02-06 23:35:19 +0100808 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100809 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100810
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200811 l2cap_conn_start(conn);
812}
813
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
815{
Marcel Holtmann01394182006-07-03 10:02:46 +0200816 struct l2cap_conn *conn = hcon->l2cap_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817
Marcel Holtmann01394182006-07-03 10:02:46 +0200818 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 return conn;
820
Marcel Holtmann01394182006-07-03 10:02:46 +0200821 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
822 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825 hcon->l2cap_data = conn;
826 conn->hcon = hcon;
827
Marcel Holtmann01394182006-07-03 10:02:46 +0200828 BT_DBG("hcon %p conn %p", hcon, conn);
829
Ville Tervoacd7d372011-02-10 22:38:49 -0300830 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
831 conn->mtu = hcon->hdev->le_mtu;
832 else
833 conn->mtu = hcon->hdev->acl_mtu;
834
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 conn->src = &hcon->hdev->bdaddr;
836 conn->dst = &hcon->dst;
837
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200838 conn->feat_mask = 0;
839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300841 rwlock_init(&conn->chan_lock);
842
843 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Ville Tervob62f3282011-02-10 22:38:50 -0300845 if (hcon->type != LE_LINK)
846 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +0000847 (unsigned long) conn);
848
Marcel Holtmann2950f212009-02-12 14:02:50 +0100849 conn->disc_reason = 0x13;
850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 return conn;
852}
853
Marcel Holtmann01394182006-07-03 10:02:46 +0200854static void l2cap_conn_del(struct hci_conn *hcon, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855{
Marcel Holtmann01394182006-07-03 10:02:46 +0200856 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300857 struct l2cap_chan *chan, *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 struct sock *sk;
859
Marcel Holtmann01394182006-07-03 10:02:46 +0200860 if (!conn)
861 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
863 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
864
Wei Yongjun7585b972009-02-25 18:29:52 +0800865 kfree_skb(conn->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
867 /* Kill channels */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300868 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300869 sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 bh_lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300871 l2cap_chan_del(chan, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 bh_unlock_sock(sk);
873 l2cap_sock_kill(sk);
874 }
875
Dave Young8e8440f2008-03-03 12:18:55 -0800876 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
877 del_timer_sync(&conn->info_timer);
Thomas Gleixner3ab22732008-02-26 17:42:56 -0800878
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 hcon->l2cap_data = NULL;
880 kfree(conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881}
882
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300883static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300885 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300886 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300887 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888}
889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
892/* Find socket with psm and source bdaddr.
893 * Returns closest match.
894 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300895static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300897 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300899 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +0000900
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300901 list_for_each_entry(c, &chan_list, global_l) {
902 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300903
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 if (state && sk->sk_state != state)
905 continue;
906
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300907 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300909 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +0200910 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300911 return c;
912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 /* Closest match */
915 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300916 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 }
918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300920 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +0000921
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300922 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923}
924
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -0300925int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300927 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 bdaddr_t *src = &bt_sk(sk)->src;
929 bdaddr_t *dst = &bt_sk(sk)->dst;
930 struct l2cap_conn *conn;
931 struct hci_conn *hcon;
932 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +0200933 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +0200934 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
Marcel Holtmannf29972d2009-02-12 05:07:45 +0100936 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300937 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938
Gustavo F. Padovanaf05b302009-04-20 01:31:08 -0300939 hdev = hci_get_route(dst, src);
940 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 return -EHOSTUNREACH;
942
943 hci_dev_lock_bh(hdev);
944
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300945 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +0200946
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300947 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -0300948 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300949 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -0300950 else
951 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300952 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -0300953
Ville Tervo30e76272011-02-22 16:10:53 -0300954 if (IS_ERR(hcon)) {
955 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -0300957 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 conn = l2cap_conn_add(hcon, 0);
960 if (!conn) {
961 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -0300962 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 goto done;
964 }
965
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 /* Update source addr of the socket */
967 bacpy(src, conn->src);
968
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300969 l2cap_chan_add(conn, chan);
970
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 sk->sk_state = BT_CONNECT;
972 l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
973
974 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovanbd3c9e22010-05-01 16:15:42 -0300975 if (sk->sk_type != SOCK_SEQPACKET &&
976 sk->sk_type != SOCK_STREAM) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 l2cap_sock_clear_timer(sk);
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300978 if (l2cap_check_security(chan))
Johan Hedbergd00ef242011-01-19 12:06:51 +0530979 sk->sk_state = BT_CONNECTED;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200980 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300981 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 }
983
Ville Tervo30e76272011-02-22 16:10:53 -0300984 err = 0;
985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986done:
987 hci_dev_unlock_bh(hdev);
988 hci_dev_put(hdev);
989 return err;
990}
991
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -0200992int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -0300993{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300994 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -0300995 DECLARE_WAITQUEUE(wait, current);
996 int err = 0;
997 int timeo = HZ/5;
998
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +0200999 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001000 while ((chan->unacked_frames > 0 && chan->conn)) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001001 set_current_state(TASK_INTERRUPTIBLE);
1002
1003 if (!timeo)
1004 timeo = HZ/5;
1005
1006 if (signal_pending(current)) {
1007 err = sock_intr_errno(timeo);
1008 break;
1009 }
1010
1011 release_sock(sk);
1012 timeo = schedule_timeout(timeo);
1013 lock_sock(sk);
1014
1015 err = sock_error(sk);
1016 if (err)
1017 break;
1018 }
1019 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001020 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001021 return err;
1022}
1023
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001024static void l2cap_monitor_timeout(unsigned long arg)
1025{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001026 struct l2cap_chan *chan = (void *) arg;
1027 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001028
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001029 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001030
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001031 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001032 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001033 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001034 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001035 return;
1036 }
1037
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001038 chan->retry_count++;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001039 __mod_monitor_timer();
1040
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001041 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001042 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001043}
1044
1045static void l2cap_retrans_timeout(unsigned long arg)
1046{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001047 struct l2cap_chan *chan = (void *) arg;
1048 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001049
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001050 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001051
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001052 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001053 chan->retry_count = 1;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001054 __mod_monitor_timer();
1055
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001056 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001057
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001058 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001059 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001060}
1061
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001062static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001063{
1064 struct sk_buff *skb;
1065
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001066 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001067 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001068 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001069 break;
1070
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001071 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001072 kfree_skb(skb);
1073
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001074 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001075 }
1076
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001077 if (!chan->unacked_frames)
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001078 del_timer(&chan->retrans_timer);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001079}
1080
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001081void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001082{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001083 struct hci_conn *hcon = chan->conn->hcon;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001084 u16 flags;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001085
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001086 BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001087
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001088 if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001089 flags = ACL_START_NO_FLUSH;
1090 else
1091 flags = ACL_START;
1092
1093 hci_send_acl(hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001094}
1095
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001096void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001097{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001098 struct sk_buff *skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001099 u16 control, fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001100
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001101 while ((skb = skb_dequeue(&chan->tx_q))) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001102 control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001103 control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001104 put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001105
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001106 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001107 fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
1108 put_unaligned_le16(fcs, skb->data + skb->len - 2);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001109 }
1110
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001111 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001112
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001113 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001114 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001115}
1116
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001117static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001118{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001119 struct sk_buff *skb, *tx_skb;
1120 u16 control, fcs;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001121
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001122 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001123 if (!skb)
1124 return;
1125
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001126 do {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001127 if (bt_cb(skb)->tx_seq == tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001128 break;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001129
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001130 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001131 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001132
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001133 } while ((skb = skb_queue_next(&chan->tx_q, skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001134
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001135 if (chan->remote_max_tx &&
1136 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001137 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001138 return;
1139 }
1140
1141 tx_skb = skb_clone(skb, GFP_ATOMIC);
1142 bt_cb(skb)->retries++;
1143 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Ruiyi Zhanga429b512011-04-18 11:04:30 +08001144 control &= L2CAP_CTRL_SAR;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001145
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001146 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001147 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001148 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001149 }
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001150
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001151 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001152 | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001153
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001154 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1155
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001156 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001157 fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
1158 put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
1159 }
1160
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001161 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001162}
1163
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001164int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001165{
1166 struct sk_buff *skb, *tx_skb;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001167 struct sock *sk = chan->sk;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001168 u16 control, fcs;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001169 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001170
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001171 if (sk->sk_state != BT_CONNECTED)
1172 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001173
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001174 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001175
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001176 if (chan->remote_max_tx &&
1177 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001178 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001179 break;
1180 }
1181
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001182 tx_skb = skb_clone(skb, GFP_ATOMIC);
1183
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001184 bt_cb(skb)->retries++;
1185
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001186 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001187 control &= L2CAP_CTRL_SAR;
1188
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001189 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001190 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001191 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001192 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001193 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
1194 | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001195 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1196
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001197
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001198 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001199 fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
1200 put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
1201 }
1202
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001203 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001204
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001205 __mod_retrans_timer();
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001206
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001207 bt_cb(skb)->tx_seq = chan->next_tx_seq;
1208 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001209
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301210 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001211 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301212
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001213 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001214
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001215 if (skb_queue_is_last(&chan->tx_q, skb))
1216 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001217 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001218 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001219
1220 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001221 }
1222
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001223 return nsent;
1224}
1225
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001226static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001227{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001228 int ret;
1229
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001230 if (!skb_queue_empty(&chan->tx_q))
1231 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001232
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001233 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001234 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001235 return ret;
1236}
1237
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001238static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001239{
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001240 u16 control = 0;
1241
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001242 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001243
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001244 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001245 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001246 chan->conn_state |= L2CAP_CONN_RNR_SENT;
1247 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001248 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001249 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001250
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001251 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001252 return;
1253
1254 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001255 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001256}
1257
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001258static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001259{
1260 struct srej_list *tail;
1261 u16 control;
1262
1263 control = L2CAP_SUPER_SELECT_REJECT;
1264 control |= L2CAP_CTRL_FINAL;
1265
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001266 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001267 control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
1268
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001269 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001270}
1271
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001272static 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 -07001273{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001274 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001275 struct sk_buff **frag;
1276 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001278 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001279 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
1281 sent += count;
1282 len -= count;
1283
1284 /* Continuation fragments (no L2CAP header) */
1285 frag = &skb_shinfo(skb)->frag_list;
1286 while (len) {
1287 count = min_t(unsigned int, conn->mtu, len);
1288
1289 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1290 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001291 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001292 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1293 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294
1295 sent += count;
1296 len -= count;
1297
1298 frag = &(*frag)->next;
1299 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300
1301 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001302}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001304struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001305{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001306 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001307 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001308 struct sk_buff *skb;
1309 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1310 struct l2cap_hdr *lh;
1311
1312 BT_DBG("sk %p len %d", sk, (int)len);
1313
1314 count = min_t(unsigned int, (conn->mtu - hlen), len);
1315 skb = bt_skb_send_alloc(sk, count + hlen,
1316 msg->msg_flags & MSG_DONTWAIT, &err);
1317 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001318 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001319
1320 /* Create L2CAP header */
1321 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001322 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001323 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001324 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001325
1326 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1327 if (unlikely(err < 0)) {
1328 kfree_skb(skb);
1329 return ERR_PTR(err);
1330 }
1331 return skb;
1332}
1333
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001334struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001335{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001336 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001337 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001338 struct sk_buff *skb;
1339 int err, count, hlen = L2CAP_HDR_SIZE;
1340 struct l2cap_hdr *lh;
1341
1342 BT_DBG("sk %p len %d", sk, (int)len);
1343
1344 count = min_t(unsigned int, (conn->mtu - hlen), len);
1345 skb = bt_skb_send_alloc(sk, count + hlen,
1346 msg->msg_flags & MSG_DONTWAIT, &err);
1347 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001348 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001349
1350 /* Create L2CAP header */
1351 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001352 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001353 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1354
1355 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1356 if (unlikely(err < 0)) {
1357 kfree_skb(skb);
1358 return ERR_PTR(err);
1359 }
1360 return skb;
1361}
1362
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001363struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001364{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001365 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001366 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001367 struct sk_buff *skb;
1368 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1369 struct l2cap_hdr *lh;
1370
1371 BT_DBG("sk %p len %d", sk, (int)len);
1372
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001373 if (!conn)
1374 return ERR_PTR(-ENOTCONN);
1375
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001376 if (sdulen)
1377 hlen += 2;
1378
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001379 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001380 hlen += 2;
1381
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001382 count = min_t(unsigned int, (conn->mtu - hlen), len);
1383 skb = bt_skb_send_alloc(sk, count + hlen,
1384 msg->msg_flags & MSG_DONTWAIT, &err);
1385 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001386 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001387
1388 /* Create L2CAP header */
1389 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001390 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001391 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1392 put_unaligned_le16(control, skb_put(skb, 2));
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001393 if (sdulen)
1394 put_unaligned_le16(sdulen, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001395
1396 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1397 if (unlikely(err < 0)) {
1398 kfree_skb(skb);
1399 return ERR_PTR(err);
1400 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001401
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001402 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001403 put_unaligned_le16(0, skb_put(skb, 2));
1404
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001405 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001406 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407}
1408
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001409int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001410{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001411 struct sk_buff *skb;
1412 struct sk_buff_head sar_queue;
1413 u16 control;
1414 size_t size = 0;
1415
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001416 skb_queue_head_init(&sar_queue);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001417 control = L2CAP_SDU_START;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001418 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001419 if (IS_ERR(skb))
1420 return PTR_ERR(skb);
1421
1422 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001423 len -= chan->remote_mps;
1424 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001425
1426 while (len > 0) {
1427 size_t buflen;
1428
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001429 if (len > chan->remote_mps) {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001430 control = L2CAP_SDU_CONTINUE;
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001431 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001432 } else {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001433 control = L2CAP_SDU_END;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001434 buflen = len;
1435 }
1436
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001437 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001438 if (IS_ERR(skb)) {
1439 skb_queue_purge(&sar_queue);
1440 return PTR_ERR(skb);
1441 }
1442
1443 __skb_queue_tail(&sar_queue, skb);
1444 len -= buflen;
1445 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001446 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001447 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1448 if (chan->tx_send_head == NULL)
1449 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001450
1451 return size;
1452}
1453
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454static void l2cap_chan_ready(struct sock *sk)
1455{
1456 struct sock *parent = bt_sk(sk)->parent;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001457 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458
1459 BT_DBG("sk %p, parent %p", sk, parent);
1460
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001461 chan->conf_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 l2cap_sock_clear_timer(sk);
1463
1464 if (!parent) {
1465 /* Outgoing channel.
1466 * Wake up socket sleeping on connect.
1467 */
1468 sk->sk_state = BT_CONNECTED;
1469 sk->sk_state_change(sk);
1470 } else {
1471 /* Incoming channel.
1472 * Wake up socket sleeping on accept.
1473 */
1474 parent->sk_data_ready(parent, 0);
1475 }
1476}
1477
1478/* Copy frame to all raw sockets on that connection */
1479static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1480{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001482 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483
1484 BT_DBG("conn %p", conn);
1485
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001486 read_lock(&conn->chan_lock);
1487 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001488 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 if (sk->sk_type != SOCK_RAW)
1490 continue;
1491
1492 /* Don't send frame to the socket it came from */
1493 if (skb->sk == sk)
1494 continue;
Gustavo F. Padovanaf05b302009-04-20 01:31:08 -03001495 nskb = skb_clone(skb, GFP_ATOMIC);
1496 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 continue;
1498
1499 if (sock_queue_rcv_skb(sk, nskb))
1500 kfree_skb(nskb);
1501 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001502 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503}
1504
1505/* ---- L2CAP signalling commands ---- */
1506static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1507 u8 code, u8 ident, u16 dlen, void *data)
1508{
1509 struct sk_buff *skb, **frag;
1510 struct l2cap_cmd_hdr *cmd;
1511 struct l2cap_hdr *lh;
1512 int len, count;
1513
Gustavo F. Padovanaf05b302009-04-20 01:31:08 -03001514 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1515 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516
1517 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1518 count = min_t(unsigned int, conn->mtu, len);
1519
1520 skb = bt_skb_alloc(count, GFP_ATOMIC);
1521 if (!skb)
1522 return NULL;
1523
1524 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001525 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001526
1527 if (conn->hcon->type == LE_LINK)
1528 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1529 else
1530 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
1532 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1533 cmd->code = code;
1534 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001535 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 if (dlen) {
1538 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1539 memcpy(skb_put(skb, count), data, count);
1540 data += count;
1541 }
1542
1543 len -= skb->len;
1544
1545 /* Continuation fragments (no L2CAP header) */
1546 frag = &skb_shinfo(skb)->frag_list;
1547 while (len) {
1548 count = min_t(unsigned int, conn->mtu, len);
1549
1550 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1551 if (!*frag)
1552 goto fail;
1553
1554 memcpy(skb_put(*frag, count), data, count);
1555
1556 len -= count;
1557 data += count;
1558
1559 frag = &(*frag)->next;
1560 }
1561
1562 return skb;
1563
1564fail:
1565 kfree_skb(skb);
1566 return NULL;
1567}
1568
1569static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1570{
1571 struct l2cap_conf_opt *opt = *ptr;
1572 int len;
1573
1574 len = L2CAP_CONF_OPT_SIZE + opt->len;
1575 *ptr += len;
1576
1577 *type = opt->type;
1578 *olen = opt->len;
1579
1580 switch (opt->len) {
1581 case 1:
1582 *val = *((u8 *) opt->val);
1583 break;
1584
1585 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001586 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 break;
1588
1589 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001590 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 break;
1592
1593 default:
1594 *val = (unsigned long) opt->val;
1595 break;
1596 }
1597
1598 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1599 return len;
1600}
1601
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1603{
1604 struct l2cap_conf_opt *opt = *ptr;
1605
1606 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1607
1608 opt->type = type;
1609 opt->len = len;
1610
1611 switch (len) {
1612 case 1:
1613 *((u8 *) opt->val) = val;
1614 break;
1615
1616 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001617 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 break;
1619
1620 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001621 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 break;
1623
1624 default:
1625 memcpy(opt->val, (void *) val, len);
1626 break;
1627 }
1628
1629 *ptr += L2CAP_CONF_OPT_SIZE + len;
1630}
1631
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001632static void l2cap_ack_timeout(unsigned long arg)
1633{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001634 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001635
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001636 bh_lock_sock(chan->sk);
1637 l2cap_send_ack(chan);
1638 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001639}
1640
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001641static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001642{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001643 struct sock *sk = chan->sk;
1644
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001645 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001646 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001647 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001648 chan->num_acked = 0;
1649 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001650
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001651 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1652 (unsigned long) chan);
1653 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1654 (unsigned long) chan);
1655 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001656
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001657 skb_queue_head_init(&chan->srej_q);
1658 skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001659
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001660 INIT_LIST_HEAD(&chan->srej_l);
1661
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03001662 INIT_WORK(&chan->busy_work, l2cap_busy_work);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001663
1664 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001665}
1666
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001667static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1668{
1669 switch (mode) {
1670 case L2CAP_MODE_STREAMING:
1671 case L2CAP_MODE_ERTM:
1672 if (l2cap_mode_supported(mode, remote_feat_mask))
1673 return mode;
1674 /* fall through */
1675 default:
1676 return L2CAP_MODE_BASIC;
1677 }
1678}
1679
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03001680static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001681{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001683 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 void *ptr = req->data;
1685
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001686 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001688 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001689 goto done;
1690
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001691 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001692 case L2CAP_MODE_STREAMING:
1693 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001694 if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001695 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001696
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03001697 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001698 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001699 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001700 break;
1701 }
1702
1703done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001704 if (chan->imtu != L2CAP_DEFAULT_MTU)
1705 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan79906812011-01-24 16:01:43 -02001706
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001707 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001708 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001709 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
1710 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001711 break;
1712
Gustavo F. Padovan62547752010-06-08 20:05:31 -03001713 rfc.mode = L2CAP_MODE_BASIC;
1714 rfc.txwin_size = 0;
1715 rfc.max_transmit = 0;
1716 rfc.retrans_timeout = 0;
1717 rfc.monitor_timeout = 0;
1718 rfc.max_pdu_size = 0;
1719
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001720 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1721 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001722 break;
1723
1724 case L2CAP_MODE_ERTM:
1725 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001726 rfc.txwin_size = chan->tx_win;
1727 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001728 rfc.retrans_timeout = 0;
1729 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001730 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001731 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1732 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001733
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001734 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1735 (unsigned long) &rfc);
1736
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001737 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001738 break;
1739
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001740 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001741 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001742 chan->fcs = L2CAP_FCS_NONE;
1743 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001744 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001745 break;
1746
1747 case L2CAP_MODE_STREAMING:
1748 rfc.mode = L2CAP_MODE_STREAMING;
1749 rfc.txwin_size = 0;
1750 rfc.max_transmit = 0;
1751 rfc.retrans_timeout = 0;
1752 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001753 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001754 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1755 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001756
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001757 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1758 (unsigned long) &rfc);
1759
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001760 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001761 break;
1762
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001763 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001764 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001765 chan->fcs = L2CAP_FCS_NONE;
1766 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001767 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001768 break;
1769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001771 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001772 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774 return ptr - data;
1775}
1776
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001777static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001779 struct l2cap_conf_rsp *rsp = data;
1780 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001781 void *req = chan->conf_req;
1782 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001783 int type, hint, olen;
1784 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02001785 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Marcel Holtmann861d6882007-10-20 13:37:06 +02001786 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001787 u16 result = L2CAP_CONF_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001789 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01001790
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001791 while (len >= L2CAP_CONF_OPT_SIZE) {
1792 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03001794 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07001795 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001796
1797 switch (type) {
1798 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02001799 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001800 break;
1801
1802 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001803 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001804 break;
1805
1806 case L2CAP_CONF_QOS:
1807 break;
1808
Marcel Holtmann6464f352007-10-20 13:39:51 +02001809 case L2CAP_CONF_RFC:
1810 if (olen == sizeof(rfc))
1811 memcpy(&rfc, (void *) val, olen);
1812 break;
1813
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001814 case L2CAP_CONF_FCS:
1815 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001816 chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001817
1818 break;
1819
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001820 default:
1821 if (hint)
1822 break;
1823
1824 result = L2CAP_CONF_UNKNOWN;
1825 *((u8 *) ptr++) = type;
1826 break;
1827 }
1828 }
1829
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001830 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001831 goto done;
1832
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001833 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001834 case L2CAP_MODE_STREAMING:
1835 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001836 if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001837 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001838 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001839 break;
1840 }
1841
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001842 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001843 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03001844
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001845 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001846 }
1847
1848done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001849 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001850 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001851 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001852
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001853 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001854 return -ECONNREFUSED;
1855
1856 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
1857 sizeof(rfc), (unsigned long) &rfc);
1858 }
1859
1860
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001861 if (result == L2CAP_CONF_SUCCESS) {
1862 /* Configure output options and let the other side know
1863 * which ones we don't like. */
1864
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001865 if (mtu < L2CAP_DEFAULT_MIN_MTU)
1866 result = L2CAP_CONF_UNACCEPT;
1867 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001868 chan->omtu = mtu;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001869 chan->conf_state |= L2CAP_CONF_MTU_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001870 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001871 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001872
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001873 switch (rfc.mode) {
1874 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001875 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001876 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001877 break;
1878
1879 case L2CAP_MODE_ERTM:
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001880 chan->remote_tx_win = rfc.txwin_size;
1881 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07001882
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001883 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
1884 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03001885
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001886 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001887
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03001888 rfc.retrans_timeout =
1889 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
1890 rfc.monitor_timeout =
1891 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001892
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001893 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03001894
1895 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
1896 sizeof(rfc), (unsigned long) &rfc);
1897
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001898 break;
1899
1900 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001901 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
1902 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03001903
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001904 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001905
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001906 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03001907
1908 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
1909 sizeof(rfc), (unsigned long) &rfc);
1910
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001911 break;
1912
1913 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02001914 result = L2CAP_CONF_UNACCEPT;
1915
1916 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001917 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02001918 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001919
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001920 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001921 chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001922 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001923 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001924 rsp->result = cpu_to_le16(result);
1925 rsp->flags = cpu_to_le16(0x0000);
1926
1927 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928}
1929
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001930static 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 -03001931{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001932 struct l2cap_conf_req *req = data;
1933 void *ptr = req->data;
1934 int type, olen;
1935 unsigned long val;
1936 struct l2cap_conf_rfc rfc;
1937
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001938 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001939
1940 while (len >= L2CAP_CONF_OPT_SIZE) {
1941 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
1942
1943 switch (type) {
1944 case L2CAP_CONF_MTU:
1945 if (val < L2CAP_DEFAULT_MIN_MTU) {
1946 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001947 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001948 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001949 chan->imtu = val;
1950 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001951 break;
1952
1953 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001954 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001955 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001956 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001957 break;
1958
1959 case L2CAP_CONF_RFC:
1960 if (olen == sizeof(rfc))
1961 memcpy(&rfc, (void *)val, olen);
1962
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001963 if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001964 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001965 return -ECONNREFUSED;
1966
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001967 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001968
1969 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
1970 sizeof(rfc), (unsigned long) &rfc);
1971 break;
1972 }
1973 }
1974
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001975 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03001976 return -ECONNREFUSED;
1977
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001978 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03001979
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001980 if (*result == L2CAP_CONF_SUCCESS) {
1981 switch (rfc.mode) {
1982 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001983 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
1984 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
1985 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001986 break;
1987 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001988 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001989 }
1990 }
1991
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001992 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001993 req->flags = cpu_to_le16(0x0000);
1994
1995 return ptr - data;
1996}
1997
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001998static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999{
2000 struct l2cap_conf_rsp *rsp = data;
2001 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002003 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002005 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002006 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002007 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
2009 return ptr - data;
2010}
2011
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002012void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002013{
2014 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002015 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002016 u8 buf[128];
2017
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002018 rsp.scid = cpu_to_le16(chan->dcid);
2019 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002020 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2021 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2022 l2cap_send_cmd(conn, chan->ident,
2023 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2024
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002025 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002026 return;
2027
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002028 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002029 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2030 l2cap_build_conf_req(chan, buf), buf);
2031 chan->num_conf_req++;
2032}
2033
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002034static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002035{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002036 int type, olen;
2037 unsigned long val;
2038 struct l2cap_conf_rfc rfc;
2039
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002040 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002041
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002042 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002043 return;
2044
2045 while (len >= L2CAP_CONF_OPT_SIZE) {
2046 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2047
2048 switch (type) {
2049 case L2CAP_CONF_RFC:
2050 if (olen == sizeof(rfc))
2051 memcpy(&rfc, (void *)val, olen);
2052 goto done;
2053 }
2054 }
2055
2056done:
2057 switch (rfc.mode) {
2058 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002059 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2060 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2061 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002062 break;
2063 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002064 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002065 }
2066}
2067
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002068static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2069{
2070 struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
2071
2072 if (rej->reason != 0x0000)
2073 return 0;
2074
2075 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2076 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002077 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002078
2079 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002080 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002081
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002082 l2cap_conn_start(conn);
2083 }
2084
2085 return 0;
2086}
2087
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2089{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2091 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002092 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002093 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002094 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095
2096 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002097 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098
2099 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2100
2101 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002102 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2103 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002104 result = L2CAP_CR_BAD_PSM;
2105 goto sendresp;
2106 }
2107
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002108 parent = pchan->sk;
2109
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002110 bh_lock_sock(parent);
2111
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002112 /* Check if the ACL is secure enough (if not SDP) */
2113 if (psm != cpu_to_le16(0x0001) &&
2114 !hci_conn_check_link_mode(conn->hcon)) {
Marcel Holtmann2950f212009-02-12 14:02:50 +01002115 conn->disc_reason = 0x05;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002116 result = L2CAP_CR_SEC_BLOCK;
2117 goto response;
2118 }
2119
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 result = L2CAP_CR_NO_MEM;
2121
2122 /* Check for backlog size */
2123 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002124 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 goto response;
2126 }
2127
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002128 sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 if (!sk)
2130 goto response;
2131
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002132 chan = l2cap_chan_create(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002133 if (!chan) {
2134 l2cap_sock_kill(sk);
2135 goto response;
2136 }
2137
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03002138 l2cap_pi(sk)->chan = chan;
2139
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002140 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
2142 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002143 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2144 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 sock_set_flag(sk, SOCK_ZAPPED);
2146 l2cap_sock_kill(sk);
2147 goto response;
2148 }
2149
2150 hci_conn_hold(conn->hcon);
2151
2152 l2cap_sock_init(sk, parent);
2153 bacpy(&bt_sk(sk)->src, conn->src);
2154 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002155 chan->psm = psm;
2156 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002158 bt_accept_enqueue(parent, sk);
2159
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002160 __l2cap_chan_add(conn, chan);
2161
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002162 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163
2164 l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
2165
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002166 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167
Marcel Holtmann984947d2009-02-06 23:35:19 +01002168 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03002169 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002170 if (bt_sk(sk)->defer_setup) {
2171 sk->sk_state = BT_CONNECT2;
2172 result = L2CAP_CR_PEND;
2173 status = L2CAP_CS_AUTHOR_PEND;
2174 parent->sk_data_ready(parent, 0);
2175 } else {
2176 sk->sk_state = BT_CONFIG;
2177 result = L2CAP_CR_SUCCESS;
2178 status = L2CAP_CS_NO_INFO;
2179 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002180 } else {
2181 sk->sk_state = BT_CONNECT2;
2182 result = L2CAP_CR_PEND;
2183 status = L2CAP_CS_AUTHEN_PEND;
2184 }
2185 } else {
2186 sk->sk_state = BT_CONNECT2;
2187 result = L2CAP_CR_PEND;
2188 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 }
2190
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002191 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192
2193response:
2194 bh_unlock_sock(parent);
2195
2196sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002197 rsp.scid = cpu_to_le16(scid);
2198 rsp.dcid = cpu_to_le16(dcid);
2199 rsp.result = cpu_to_le16(result);
2200 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002202
2203 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2204 struct l2cap_info_req info;
2205 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2206
2207 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2208 conn->info_ident = l2cap_get_ident(conn);
2209
2210 mod_timer(&conn->info_timer, jiffies +
2211 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2212
2213 l2cap_send_cmd(conn, conn->info_ident,
2214 L2CAP_INFO_REQ, sizeof(info), &info);
2215 }
2216
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002217 if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002218 result == L2CAP_CR_SUCCESS) {
2219 u8 buf[128];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002220 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002221 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002222 l2cap_build_conf_req(chan, buf), buf);
2223 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002224 }
2225
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 return 0;
2227}
2228
2229static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2230{
2231 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2232 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002233 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 struct sock *sk;
2235 u8 req[128];
2236
2237 scid = __le16_to_cpu(rsp->scid);
2238 dcid = __le16_to_cpu(rsp->dcid);
2239 result = __le16_to_cpu(rsp->result);
2240 status = __le16_to_cpu(rsp->status);
2241
2242 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2243
2244 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002245 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002246 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002247 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002249 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002250 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002251 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 }
2253
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002254 sk = chan->sk;
2255
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 switch (result) {
2257 case L2CAP_CR_SUCCESS:
2258 sk->sk_state = BT_CONFIG;
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002259 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002260 chan->dcid = dcid;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002261 chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002262
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002263 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002264 break;
2265
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002266 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002267
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002269 l2cap_build_conf_req(chan, req), req);
2270 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002271 break;
2272
2273 case L2CAP_CR_PEND:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002274 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 break;
2276
2277 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002278 /* don't delete l2cap channel if sk is owned by user */
2279 if (sock_owned_by_user(sk)) {
2280 sk->sk_state = BT_DISCONN;
2281 l2cap_sock_clear_timer(sk);
2282 l2cap_sock_set_timer(sk, HZ / 5);
2283 break;
2284 }
2285
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002286 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 break;
2288 }
2289
2290 bh_unlock_sock(sk);
2291 return 0;
2292}
2293
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002294static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002295{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002296 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
2297
Mat Martineau8c462b62010-08-24 15:35:42 -07002298 /* FCS is enabled only in ERTM or streaming mode, if one or both
2299 * sides request it.
2300 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002301 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002302 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002303 else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002304 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002305}
2306
Al Viro88219a02007-07-29 00:17:25 -07002307static 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 -07002308{
2309 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2310 u16 dcid, flags;
2311 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002312 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002314 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
2316 dcid = __le16_to_cpu(req->dcid);
2317 flags = __le16_to_cpu(req->flags);
2318
2319 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2320
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002321 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002322 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 return -ENOENT;
2324
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002325 sk = chan->sk;
2326
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002327 if (sk->sk_state != BT_CONFIG) {
2328 struct l2cap_cmd_rej rej;
2329
2330 rej.reason = cpu_to_le16(0x0002);
2331 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2332 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002333 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002334 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002335
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002336 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002337 len = cmd_len - sizeof(*req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002338 if (chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002339 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002340 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002341 L2CAP_CONF_REJECT, flags), rsp);
2342 goto unlock;
2343 }
2344
2345 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002346 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2347 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
2349 if (flags & 0x0001) {
2350 /* Incomplete config. Send empty response. */
2351 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002352 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002353 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 goto unlock;
2355 }
2356
2357 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002358 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002359 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002360 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002362 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002364 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002365 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002366
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002367 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002368 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002369
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002370 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002371 goto unlock;
2372
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002373 if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002374 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002375
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 sk->sk_state = BT_CONNECTED;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002377
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002378 chan->next_tx_seq = 0;
2379 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002380 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002381 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002382 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002383
Linus Torvalds1da177e2005-04-16 15:20:36 -07002384 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002385 goto unlock;
2386 }
2387
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002388 if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002389 u8 buf[64];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002390 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002392 l2cap_build_conf_req(chan, buf), buf);
2393 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394 }
2395
2396unlock:
2397 bh_unlock_sock(sk);
2398 return 0;
2399}
2400
2401static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2402{
2403 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2404 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002405 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002407 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
2409 scid = __le16_to_cpu(rsp->scid);
2410 flags = __le16_to_cpu(rsp->flags);
2411 result = __le16_to_cpu(rsp->result);
2412
Gustavo F. Padovanaf05b302009-04-20 01:31:08 -03002413 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2414 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002416 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002417 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 return 0;
2419
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002420 sk = chan->sk;
2421
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 switch (result) {
2423 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002424 l2cap_conf_rfc_get(chan, rsp->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425 break;
2426
2427 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002428 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002429 char req[64];
2430
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002431 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002432 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002433 goto done;
2434 }
2435
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002436 /* throw out any old stored conf requests */
2437 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002438 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2439 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002440 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002441 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002442 goto done;
2443 }
2444
2445 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2446 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002447 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002448 if (result != L2CAP_CONF_SUCCESS)
2449 goto done;
2450 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451 }
2452
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002453 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002454 sk->sk_err = ECONNRESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 l2cap_sock_set_timer(sk, HZ * 5);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002456 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457 goto done;
2458 }
2459
2460 if (flags & 0x01)
2461 goto done;
2462
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002463 chan->conf_state |= L2CAP_CONF_INPUT_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002465 if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002466 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002467
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 sk->sk_state = BT_CONNECTED;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002469 chan->next_tx_seq = 0;
2470 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002471 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002472 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002473 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002474
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 l2cap_chan_ready(sk);
2476 }
2477
2478done:
2479 bh_unlock_sock(sk);
2480 return 0;
2481}
2482
2483static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2484{
2485 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2486 struct l2cap_disconn_rsp rsp;
2487 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002488 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 struct sock *sk;
2490
2491 scid = __le16_to_cpu(req->scid);
2492 dcid = __le16_to_cpu(req->dcid);
2493
2494 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2495
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002496 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002497 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498 return 0;
2499
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002500 sk = chan->sk;
2501
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002502 rsp.dcid = cpu_to_le16(chan->scid);
2503 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2505
2506 sk->sk_shutdown = SHUTDOWN_MASK;
2507
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002508 /* don't delete l2cap channel if sk is owned by user */
2509 if (sock_owned_by_user(sk)) {
2510 sk->sk_state = BT_DISCONN;
2511 l2cap_sock_clear_timer(sk);
2512 l2cap_sock_set_timer(sk, HZ / 5);
2513 bh_unlock_sock(sk);
2514 return 0;
2515 }
2516
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002517 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 bh_unlock_sock(sk);
2519
2520 l2cap_sock_kill(sk);
2521 return 0;
2522}
2523
2524static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2525{
2526 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
2527 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002528 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529 struct sock *sk;
2530
2531 scid = __le16_to_cpu(rsp->scid);
2532 dcid = __le16_to_cpu(rsp->dcid);
2533
2534 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
2535
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002536 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002537 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 return 0;
2539
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002540 sk = chan->sk;
2541
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002542 /* don't delete l2cap channel if sk is owned by user */
2543 if (sock_owned_by_user(sk)) {
2544 sk->sk_state = BT_DISCONN;
2545 l2cap_sock_clear_timer(sk);
2546 l2cap_sock_set_timer(sk, HZ / 5);
2547 bh_unlock_sock(sk);
2548 return 0;
2549 }
2550
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002551 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 bh_unlock_sock(sk);
2553
2554 l2cap_sock_kill(sk);
2555 return 0;
2556}
2557
2558static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2559{
2560 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 u16 type;
2562
2563 type = __le16_to_cpu(req->type);
2564
2565 BT_DBG("type 0x%4.4x", type);
2566
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002567 if (type == L2CAP_IT_FEAT_MASK) {
2568 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07002569 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002570 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2571 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2572 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03002573 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002574 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
2575 | L2CAP_FEAT_FCS;
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03002576 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002577 l2cap_send_cmd(conn, cmd->ident,
2578 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002579 } else if (type == L2CAP_IT_FIXED_CHAN) {
2580 u8 buf[12];
2581 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2582 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2583 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
2584 memcpy(buf + 4, l2cap_fixed_chan, 8);
2585 l2cap_send_cmd(conn, cmd->ident,
2586 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002587 } else {
2588 struct l2cap_info_rsp rsp;
2589 rsp.type = cpu_to_le16(type);
2590 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
2591 l2cap_send_cmd(conn, cmd->ident,
2592 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
2593 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594
2595 return 0;
2596}
2597
2598static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2599{
2600 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
2601 u16 type, result;
2602
2603 type = __le16_to_cpu(rsp->type);
2604 result = __le16_to_cpu(rsp->result);
2605
2606 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
2607
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02002608 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
2609 if (cmd->ident != conn->info_ident ||
2610 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
2611 return 0;
2612
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002613 del_timer(&conn->info_timer);
2614
Ville Tervoadb08ed2010-08-04 09:43:33 +03002615 if (result != L2CAP_IR_SUCCESS) {
2616 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2617 conn->info_ident = 0;
2618
2619 l2cap_conn_start(conn);
2620
2621 return 0;
2622 }
2623
Marcel Holtmann984947d2009-02-06 23:35:19 +01002624 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07002625 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002626
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002627 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002628 struct l2cap_info_req req;
2629 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2630
2631 conn->info_ident = l2cap_get_ident(conn);
2632
2633 l2cap_send_cmd(conn, conn->info_ident,
2634 L2CAP_INFO_REQ, sizeof(req), &req);
2635 } else {
2636 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2637 conn->info_ident = 0;
2638
2639 l2cap_conn_start(conn);
2640 }
2641 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01002642 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002643 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002644
2645 l2cap_conn_start(conn);
2646 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002647
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 return 0;
2649}
2650
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002651static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02002652 u16 to_multiplier)
2653{
2654 u16 max_latency;
2655
2656 if (min > max || min < 6 || max > 3200)
2657 return -EINVAL;
2658
2659 if (to_multiplier < 10 || to_multiplier > 3200)
2660 return -EINVAL;
2661
2662 if (max >= to_multiplier * 8)
2663 return -EINVAL;
2664
2665 max_latency = (to_multiplier * 8 / max) - 1;
2666 if (latency > 499 || latency > max_latency)
2667 return -EINVAL;
2668
2669 return 0;
2670}
2671
2672static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
2673 struct l2cap_cmd_hdr *cmd, u8 *data)
2674{
2675 struct hci_conn *hcon = conn->hcon;
2676 struct l2cap_conn_param_update_req *req;
2677 struct l2cap_conn_param_update_rsp rsp;
2678 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002679 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02002680
2681 if (!(hcon->link_mode & HCI_LM_MASTER))
2682 return -EINVAL;
2683
2684 cmd_len = __le16_to_cpu(cmd->len);
2685 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
2686 return -EPROTO;
2687
2688 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002689 min = __le16_to_cpu(req->min);
2690 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02002691 latency = __le16_to_cpu(req->latency);
2692 to_multiplier = __le16_to_cpu(req->to_multiplier);
2693
2694 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
2695 min, max, latency, to_multiplier);
2696
2697 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002698
2699 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
2700 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02002701 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
2702 else
2703 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
2704
2705 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
2706 sizeof(rsp), &rsp);
2707
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002708 if (!err)
2709 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
2710
Claudio Takahaside731152011-02-11 19:28:55 -02002711 return 0;
2712}
2713
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002714static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
2715 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
2716{
2717 int err = 0;
2718
2719 switch (cmd->code) {
2720 case L2CAP_COMMAND_REJ:
2721 l2cap_command_rej(conn, cmd, data);
2722 break;
2723
2724 case L2CAP_CONN_REQ:
2725 err = l2cap_connect_req(conn, cmd, data);
2726 break;
2727
2728 case L2CAP_CONN_RSP:
2729 err = l2cap_connect_rsp(conn, cmd, data);
2730 break;
2731
2732 case L2CAP_CONF_REQ:
2733 err = l2cap_config_req(conn, cmd, cmd_len, data);
2734 break;
2735
2736 case L2CAP_CONF_RSP:
2737 err = l2cap_config_rsp(conn, cmd, data);
2738 break;
2739
2740 case L2CAP_DISCONN_REQ:
2741 err = l2cap_disconnect_req(conn, cmd, data);
2742 break;
2743
2744 case L2CAP_DISCONN_RSP:
2745 err = l2cap_disconnect_rsp(conn, cmd, data);
2746 break;
2747
2748 case L2CAP_ECHO_REQ:
2749 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
2750 break;
2751
2752 case L2CAP_ECHO_RSP:
2753 break;
2754
2755 case L2CAP_INFO_REQ:
2756 err = l2cap_information_req(conn, cmd, data);
2757 break;
2758
2759 case L2CAP_INFO_RSP:
2760 err = l2cap_information_rsp(conn, cmd, data);
2761 break;
2762
2763 default:
2764 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
2765 err = -EINVAL;
2766 break;
2767 }
2768
2769 return err;
2770}
2771
2772static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
2773 struct l2cap_cmd_hdr *cmd, u8 *data)
2774{
2775 switch (cmd->code) {
2776 case L2CAP_COMMAND_REJ:
2777 return 0;
2778
2779 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02002780 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002781
2782 case L2CAP_CONN_PARAM_UPDATE_RSP:
2783 return 0;
2784
2785 default:
2786 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
2787 return -EINVAL;
2788 }
2789}
2790
2791static inline void l2cap_sig_channel(struct l2cap_conn *conn,
2792 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793{
2794 u8 *data = skb->data;
2795 int len = skb->len;
2796 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002797 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798
2799 l2cap_raw_recv(conn, skb);
2800
2801 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07002802 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
2804 data += L2CAP_CMD_HDR_SIZE;
2805 len -= L2CAP_CMD_HDR_SIZE;
2806
Al Viro88219a02007-07-29 00:17:25 -07002807 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808
Al Viro88219a02007-07-29 00:17:25 -07002809 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 -07002810
Al Viro88219a02007-07-29 00:17:25 -07002811 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 BT_DBG("corrupted command");
2813 break;
2814 }
2815
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002816 if (conn->hcon->type == LE_LINK)
2817 err = l2cap_le_sig_cmd(conn, &cmd, data);
2818 else
2819 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820
2821 if (err) {
2822 struct l2cap_cmd_rej rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03002823
2824 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825
2826 /* FIXME: Map err to a valid reason */
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002827 rej.reason = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
2829 }
2830
Al Viro88219a02007-07-29 00:17:25 -07002831 data += cmd_len;
2832 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 }
2834
2835 kfree_skb(skb);
2836}
2837
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002838static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002839{
2840 u16 our_fcs, rcv_fcs;
2841 int hdr_size = L2CAP_HDR_SIZE + 2;
2842
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002843 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002844 skb_trim(skb, skb->len - 2);
2845 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
2846 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
2847
2848 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03002849 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002850 }
2851 return 0;
2852}
2853
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002854static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03002855{
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03002856 u16 control = 0;
2857
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002858 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03002859
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002860 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03002861
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002862 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan64988862010-05-10 14:54:14 -03002863 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002864 l2cap_send_sframe(chan, control);
2865 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03002866 }
2867
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002868 if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
2869 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03002870
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002871 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03002872
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002873 if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002874 chan->frames_sent == 0) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03002875 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002876 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03002877 }
2878}
2879
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002880static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03002881{
2882 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03002883 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03002884
2885 bt_cb(skb)->tx_seq = tx_seq;
2886 bt_cb(skb)->sar = sar;
2887
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002888 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03002889 if (!next_skb) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002890 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03002891 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03002892 }
2893
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002894 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03002895 if (tx_seq_offset < 0)
2896 tx_seq_offset += 64;
2897
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03002898 do {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03002899 if (bt_cb(next_skb)->tx_seq == tx_seq)
2900 return -EINVAL;
2901
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03002902 next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002903 chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03002904 if (next_tx_seq_offset < 0)
2905 next_tx_seq_offset += 64;
2906
2907 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002908 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03002909 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03002910 }
2911
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002912 if (skb_queue_is_last(&chan->srej_q, next_skb))
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03002913 break;
2914
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002915 } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03002916
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002917 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03002918
2919 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03002920}
2921
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002922static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002923{
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002924 struct sk_buff *_skb;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002925 int err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002926
2927 switch (control & L2CAP_CTRL_SAR) {
2928 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002929 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002930 goto drop;
2931
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002932 err = sock_queue_rcv_skb(chan->sk, skb);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002933 if (!err)
2934 return err;
2935
2936 break;
2937
2938 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002939 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002940 goto drop;
2941
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002942 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002943
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002944 if (chan->sdu_len > chan->imtu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002945 goto disconnect;
2946
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002947 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
2948 if (!chan->sdu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002949 return -ENOMEM;
2950
2951 /* pull sdu_len bytes only after alloc, because of Local Busy
2952 * condition we have to be sure that this will be executed
2953 * only once, i.e., when alloc does not fail */
2954 skb_pull(skb, 2);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002955
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002956 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002957
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002958 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002959 chan->partial_sdu_len = skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002960 break;
2961
2962 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002963 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002964 goto disconnect;
2965
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002966 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002967 goto disconnect;
2968
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002969 chan->partial_sdu_len += skb->len;
2970 if (chan->partial_sdu_len > chan->sdu_len)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002971 goto drop;
2972
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002973 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03002974
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002975 break;
2976
2977 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002978 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002979 goto disconnect;
2980
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002981 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002982 goto disconnect;
2983
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002984 if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002985 chan->partial_sdu_len += skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002986
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002987 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002988 goto drop;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002989
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002990 if (chan->partial_sdu_len != chan->sdu_len)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002991 goto drop;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03002992
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002993 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002994 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03002995
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03002996 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002997 if (!_skb) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002998 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002999 return -ENOMEM;
3000 }
3001
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003002 err = sock_queue_rcv_skb(chan->sk, _skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003003 if (err < 0) {
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003004 kfree_skb(_skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003005 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003006 return err;
3007 }
3008
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003009 chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
3010 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003011
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003012 kfree_skb(chan->sdu);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003013 break;
3014 }
3015
3016 kfree_skb(skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003017 return 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003018
3019drop:
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003020 kfree_skb(chan->sdu);
3021 chan->sdu = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003022
3023disconnect:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003024 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003025 kfree_skb(skb);
3026 return 0;
3027}
3028
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003029static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003030{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003031 struct sk_buff *skb;
3032 u16 control;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003033 int err;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003034
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003035 while ((skb = skb_dequeue(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003036 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003037 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003038 if (err < 0) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003039 skb_queue_head(&chan->busy_q, skb);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003040 return -EBUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003041 }
3042
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003043 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003044 }
3045
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003046 if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003047 goto done;
3048
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003049 control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003050 control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003051 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003052 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003053
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003054 del_timer(&chan->retrans_timer);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003055 __mod_monitor_timer();
3056
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003057 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003058
3059done:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003060 chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
3061 chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003062
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003063 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003064
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003065 return 0;
3066}
3067
3068static void l2cap_busy_work(struct work_struct *work)
3069{
3070 DECLARE_WAITQUEUE(wait, current);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003071 struct l2cap_chan *chan =
3072 container_of(work, struct l2cap_chan, busy_work);
3073 struct sock *sk = chan->sk;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003074 int n_tries = 0, timeo = HZ/5, err;
3075 struct sk_buff *skb;
3076
3077 lock_sock(sk);
3078
3079 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003080 while ((skb = skb_peek(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003081 set_current_state(TASK_INTERRUPTIBLE);
3082
3083 if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
3084 err = -EBUSY;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003085 l2cap_send_disconn_req(chan->conn, chan, EBUSY);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003086 break;
3087 }
3088
3089 if (!timeo)
3090 timeo = HZ/5;
3091
3092 if (signal_pending(current)) {
3093 err = sock_intr_errno(timeo);
3094 break;
3095 }
3096
3097 release_sock(sk);
3098 timeo = schedule_timeout(timeo);
3099 lock_sock(sk);
3100
3101 err = sock_error(sk);
3102 if (err)
3103 break;
3104
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003105 if (l2cap_try_push_rx_skb(chan) == 0)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003106 break;
3107 }
3108
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003109 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02003110 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003111
3112 release_sock(sk);
3113}
3114
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003115static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003116{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003117 int sctrl, err;
3118
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003119 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003120 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003121 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003122 return l2cap_try_push_rx_skb(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003123
3124
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003125 }
3126
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003127 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003128 if (err >= 0) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003129 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003130 return err;
3131 }
3132
3133 /* Busy Condition */
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003134 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003135
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003136 chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003137 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003138 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003139
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003140 sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003141 sctrl |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003142 l2cap_send_sframe(chan, sctrl);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003143
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003144 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003145
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003146 del_timer(&chan->ack_timer);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003147
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003148 queue_work(_busy_wq, &chan->busy_work);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003149
3150 return err;
3151}
3152
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003153static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003154{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003155 struct sk_buff *_skb;
3156 int err = -EINVAL;
3157
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003158 /*
3159 * TODO: We have to notify the userland if some data is lost with the
3160 * Streaming Mode.
3161 */
3162
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003163 switch (control & L2CAP_CTRL_SAR) {
3164 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003165 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003166 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003167 break;
3168 }
3169
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003170 err = sock_queue_rcv_skb(chan->sk, skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003171 if (!err)
3172 return 0;
3173
3174 break;
3175
3176 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003177 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003178 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003179 break;
3180 }
3181
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003182 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003183 skb_pull(skb, 2);
3184
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003185 if (chan->sdu_len > chan->imtu) {
Gustavo F. Padovan052897c2010-05-01 16:15:40 -03003186 err = -EMSGSIZE;
3187 break;
3188 }
3189
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003190 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3191 if (!chan->sdu) {
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003192 err = -ENOMEM;
3193 break;
3194 }
3195
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003196 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003197
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003198 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003199 chan->partial_sdu_len = skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003200 err = 0;
3201 break;
3202
3203 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003204 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003205 break;
3206
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003207 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003208
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003209 chan->partial_sdu_len += skb->len;
3210 if (chan->partial_sdu_len > chan->sdu_len)
3211 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003212 else
3213 err = 0;
3214
3215 break;
3216
3217 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003218 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003219 break;
3220
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003221 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003222
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003223 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003224 chan->partial_sdu_len += skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003225
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003226 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003227 goto drop;
3228
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003229 if (chan->partial_sdu_len == chan->sdu_len) {
3230 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003231 err = sock_queue_rcv_skb(chan->sk, _skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003232 if (err < 0)
3233 kfree_skb(_skb);
3234 }
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003235 err = 0;
3236
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003237drop:
Gustavo F. Padovan6f61fd42011-03-25 20:09:37 -03003238 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003239 break;
3240 }
3241
3242 kfree_skb(skb);
3243 return err;
3244}
3245
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003246static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003247{
3248 struct sk_buff *skb;
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003249 u16 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003250
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003251 while ((skb = skb_peek(&chan->srej_q))) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003252 if (bt_cb(skb)->tx_seq != tx_seq)
3253 break;
3254
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003255 skb = skb_dequeue(&chan->srej_q);
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003256 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003257 l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003258 chan->buffer_seq_srej =
3259 (chan->buffer_seq_srej + 1) % 64;
Gustavo F. Padovan8ff50ec2010-05-10 19:34:11 -03003260 tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003261 }
3262}
3263
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003264static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003265{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003266 struct srej_list *l, *tmp;
3267 u16 control;
3268
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003269 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003270 if (l->tx_seq == tx_seq) {
3271 list_del(&l->list);
3272 kfree(l);
3273 return;
3274 }
3275 control = L2CAP_SUPER_SELECT_REJECT;
3276 control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003277 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003278 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003279 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003280 }
3281}
3282
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003283static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003284{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003285 struct srej_list *new;
3286 u16 control;
3287
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003288 while (tx_seq != chan->expected_tx_seq) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003289 control = L2CAP_SUPER_SELECT_REJECT;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003290 control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003291 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003292
3293 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003294 new->tx_seq = chan->expected_tx_seq;
3295 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003296 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003297 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003298 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003299}
3300
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003301static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003302{
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003303 u8 tx_seq = __get_txseq(rx_control);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003304 u8 req_seq = __get_reqseq(rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003305 u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003306 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003307 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003308 int err = 0;
3309
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003310 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
3311 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003312
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003313 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003314 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003315 del_timer(&chan->monitor_timer);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003316 if (chan->unacked_frames > 0)
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003317 __mod_retrans_timer();
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003318 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003319 }
3320
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003321 chan->expected_ack_seq = req_seq;
3322 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003323
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003324 if (tx_seq == chan->expected_tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003325 goto expected;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003326
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003327 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003328 if (tx_seq_offset < 0)
3329 tx_seq_offset += 64;
3330
3331 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003332 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003333 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003334 goto drop;
3335 }
3336
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003337 if (chan->conn_state == L2CAP_CONN_LOCAL_BUSY)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003338 goto drop;
3339
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003340 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003341 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003342
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003343 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003344 struct srej_list, list);
3345 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003346 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003347 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003348
3349 list_del(&first->list);
3350 kfree(first);
3351
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003352 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003353 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003354 chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
3355 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003356 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003357 }
3358 } else {
3359 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003360
3361 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003362 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003363 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003364
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003365 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003366 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003367 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003368 return 0;
3369 }
3370 }
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003371 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003372 }
3373 } else {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003374 expected_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003375 (chan->expected_tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003376 if (expected_tx_seq_offset < 0)
3377 expected_tx_seq_offset += 64;
3378
3379 /* duplicated tx_seq */
3380 if (tx_seq_offset < expected_tx_seq_offset)
3381 goto drop;
3382
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003383 chan->conn_state |= L2CAP_CONN_SREJ_SENT;
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003384
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003385 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003386
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003387 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003388 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003389
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003390 __skb_queue_head_init(&chan->srej_q);
3391 __skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003392 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003393
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003394 chan->conn_state |= L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003395
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003396 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003397
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003398 del_timer(&chan->ack_timer);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003399 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003400 return 0;
3401
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003402expected:
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003403 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003404
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003405 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003406 bt_cb(skb)->tx_seq = tx_seq;
3407 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003408 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003409 return 0;
3410 }
3411
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003412 err = l2cap_push_rx_skb(chan, skb, rx_control);
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003413 if (err < 0)
3414 return 0;
3415
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003416 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003417 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3418 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003419 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003420 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003421 }
3422
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003423 __mod_ack_timer();
3424
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003425 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3426 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003427 l2cap_send_ack(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003428
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003429 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003430
3431drop:
3432 kfree_skb(skb);
3433 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003434}
3435
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003436static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003437{
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003438 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003439 rx_control);
3440
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003441 chan->expected_ack_seq = __get_reqseq(rx_control);
3442 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003443
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003444 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003445 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3446 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
3447 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003448 (chan->unacked_frames > 0))
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003449 __mod_retrans_timer();
3450
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003451 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3452 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003453 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003454 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003455 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003456
3457 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003458 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003459
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003460 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3461 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003462 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003463 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003464
3465 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003466 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003467 (chan->unacked_frames > 0))
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003468 __mod_retrans_timer();
3469
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003470 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3471 if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
3472 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003473 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003474 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003475 }
3476}
3477
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003478static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003479{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003480 u8 tx_seq = __get_reqseq(rx_control);
3481
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003482 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003483
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003484 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003485
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003486 chan->expected_ack_seq = tx_seq;
3487 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003488
3489 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003490 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3491 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003492 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003493 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003494 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003495 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003496
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003497 if (chan->conn_state & L2CAP_CONN_WAIT_F)
3498 chan->conn_state |= L2CAP_CONN_REJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003499 }
3500}
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003501static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003502{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003503 u8 tx_seq = __get_reqseq(rx_control);
3504
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003505 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003506
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003507 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003508
3509 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003510 chan->expected_ack_seq = tx_seq;
3511 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003512
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003513 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3514 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003515
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003516 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003517
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003518 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003519 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003520 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003521 }
3522 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003523 if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003524 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003525 chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003526 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003527 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003528 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003529 l2cap_retransmit_one_frame(chan, tx_seq);
3530 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003531 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003532 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003533 }
3534 }
3535}
3536
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003537static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003538{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003539 u8 tx_seq = __get_reqseq(rx_control);
3540
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003541 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003542
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003543 chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003544 chan->expected_ack_seq = tx_seq;
3545 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003546
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003547 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003548 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003549
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003550 if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003551 del_timer(&chan->retrans_timer);
Gustavo F. Padovana2e12a22010-05-05 19:58:27 -03003552 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003553 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003554 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003555 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003556
3557 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003558 l2cap_send_srejtail(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003559 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003560 l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003561}
3562
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003563static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003564{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003565 BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003566
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003567 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003568 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003569 del_timer(&chan->monitor_timer);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003570 if (chan->unacked_frames > 0)
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003571 __mod_retrans_timer();
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003572 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003573 }
3574
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003575 switch (rx_control & L2CAP_CTRL_SUPERVISE) {
3576 case L2CAP_SUPER_RCV_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003577 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003578 break;
3579
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003580 case L2CAP_SUPER_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003581 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003582 break;
3583
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003584 case L2CAP_SUPER_SELECT_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003585 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003586 break;
3587
3588 case L2CAP_SUPER_RCV_NOT_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003589 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003590 break;
3591 }
3592
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03003593 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003594 return 0;
3595}
3596
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003597static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
3598{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003599 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003600 u16 control;
3601 u8 req_seq;
3602 int len, next_tx_seq_offset, req_seq_offset;
3603
3604 control = get_unaligned_le16(skb->data);
3605 skb_pull(skb, 2);
3606 len = skb->len;
3607
3608 /*
3609 * We can just drop the corrupted I-frame here.
3610 * Receiver will miss it and start proper recovery
3611 * procedures and ask retransmission.
3612 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003613 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003614 goto drop;
3615
3616 if (__is_sar_start(control) && __is_iframe(control))
3617 len -= 2;
3618
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003619 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003620 len -= 2;
3621
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003622 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003623 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003624 goto drop;
3625 }
3626
3627 req_seq = __get_reqseq(control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003628 req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003629 if (req_seq_offset < 0)
3630 req_seq_offset += 64;
3631
3632 next_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003633 (chan->next_tx_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003634 if (next_tx_seq_offset < 0)
3635 next_tx_seq_offset += 64;
3636
3637 /* check for invalid req-seq */
3638 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003639 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003640 goto drop;
3641 }
3642
3643 if (__is_iframe(control)) {
3644 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003645 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003646 goto drop;
3647 }
3648
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003649 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003650 } else {
3651 if (len != 0) {
3652 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003653 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003654 goto drop;
3655 }
3656
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003657 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003658 }
3659
3660 return 0;
3661
3662drop:
3663 kfree_skb(skb);
3664 return 0;
3665}
3666
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
3668{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003669 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07003670 struct sock *sk = NULL;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003671 struct l2cap_pinfo *pi;
Nathan Holstein51893f82010-06-09 15:46:25 -04003672 u16 control;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003673 u8 tx_seq;
3674 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003676 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003677 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 BT_DBG("unknown cid 0x%4.4x", cid);
3679 goto drop;
3680 }
3681
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003682 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003683 pi = l2cap_pi(sk);
3684
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003685 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686
3687 if (sk->sk_state != BT_CONNECTED)
3688 goto drop;
3689
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003690 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003691 case L2CAP_MODE_BASIC:
3692 /* If socket recv buffers overflows we drop data here
3693 * which is *bad* because L2CAP has to be reliable.
3694 * But we don't have any other choice. L2CAP doesn't
3695 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003697 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003698 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003700 if (!sock_queue_rcv_skb(sk, skb))
3701 goto done;
3702 break;
3703
3704 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003705 if (!sock_owned_by_user(sk)) {
3706 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003707 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003708 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003709 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003710 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003711
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02003712 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003713
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003714 case L2CAP_MODE_STREAMING:
3715 control = get_unaligned_le16(skb->data);
3716 skb_pull(skb, 2);
3717 len = skb->len;
3718
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003719 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03003720 goto drop;
3721
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003722 if (__is_sar_start(control))
3723 len -= 2;
3724
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003725 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003726 len -= 2;
3727
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003728 if (len > chan->mps || len < 0 || __is_sframe(control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003729 goto drop;
3730
3731 tx_seq = __get_txseq(control);
3732
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003733 if (chan->expected_tx_seq == tx_seq)
3734 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003735 else
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003736 chan->expected_tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003737
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003738 l2cap_streaming_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003739
3740 goto done;
3741
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003742 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003743 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003744 break;
3745 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746
3747drop:
3748 kfree_skb(skb);
3749
3750done:
Marcel Holtmann01394182006-07-03 10:02:46 +02003751 if (sk)
3752 bh_unlock_sock(sk);
3753
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 return 0;
3755}
3756
Al Viro8e036fc2007-07-29 00:16:36 -07003757static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003759 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003760 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003762 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
3763 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 goto drop;
3765
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003766 sk = chan->sk;
3767
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00003768 bh_lock_sock(sk);
3769
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 BT_DBG("sk %p, len %d", sk, skb->len);
3771
3772 if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
3773 goto drop;
3774
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003775 if (l2cap_pi(sk)->chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776 goto drop;
3777
3778 if (!sock_queue_rcv_skb(sk, skb))
3779 goto done;
3780
3781drop:
3782 kfree_skb(skb);
3783
3784done:
Gustavo F. Padovanaf05b302009-04-20 01:31:08 -03003785 if (sk)
3786 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003787 return 0;
3788}
3789
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003790static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
3791{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003792 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003793 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003794
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003795 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
3796 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003797 goto drop;
3798
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003799 sk = chan->sk;
3800
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003801 bh_lock_sock(sk);
3802
3803 BT_DBG("sk %p, len %d", sk, skb->len);
3804
3805 if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
3806 goto drop;
3807
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003808 if (l2cap_pi(sk)->chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003809 goto drop;
3810
3811 if (!sock_queue_rcv_skb(sk, skb))
3812 goto done;
3813
3814drop:
3815 kfree_skb(skb);
3816
3817done:
3818 if (sk)
3819 bh_unlock_sock(sk);
3820 return 0;
3821}
3822
Linus Torvalds1da177e2005-04-16 15:20:36 -07003823static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
3824{
3825 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07003826 u16 cid, len;
3827 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003828
3829 skb_pull(skb, L2CAP_HDR_SIZE);
3830 cid = __le16_to_cpu(lh->cid);
3831 len = __le16_to_cpu(lh->len);
3832
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003833 if (len != skb->len) {
3834 kfree_skb(skb);
3835 return;
3836 }
3837
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 BT_DBG("len %d, cid 0x%4.4x", len, cid);
3839
3840 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003841 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03003842 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 l2cap_sig_channel(conn, skb);
3844 break;
3845
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03003846 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003847 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 skb_pull(skb, 2);
3849 l2cap_conless_channel(conn, psm, skb);
3850 break;
3851
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003852 case L2CAP_CID_LE_DATA:
3853 l2cap_att_channel(conn, cid, skb);
3854 break;
3855
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 default:
3857 l2cap_data_channel(conn, cid, skb);
3858 break;
3859 }
3860}
3861
3862/* ---- L2CAP interface with lower layer (HCI) ---- */
3863
3864static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
3865{
3866 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003867 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868
3869 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03003870 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871
3872 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
3873
3874 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003875 read_lock(&chan_list_lock);
3876 list_for_each_entry(c, &chan_list, global_l) {
3877 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03003878
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 if (sk->sk_state != BT_LISTEN)
3880 continue;
3881
3882 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01003883 lm1 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003884 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01003885 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01003887 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
3888 lm2 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003889 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01003890 lm2 |= HCI_LM_MASTER;
3891 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003893 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894
3895 return exact ? lm1 : lm2;
3896}
3897
3898static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
3899{
Marcel Holtmann01394182006-07-03 10:02:46 +02003900 struct l2cap_conn *conn;
3901
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
3903
Ville Tervoacd7d372011-02-10 22:38:49 -03003904 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03003905 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906
3907 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 conn = l2cap_conn_add(hcon, status);
3909 if (conn)
3910 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02003911 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07003912 l2cap_conn_del(hcon, bt_err(status));
3913
3914 return 0;
3915}
3916
Marcel Holtmann2950f212009-02-12 14:02:50 +01003917static int l2cap_disconn_ind(struct hci_conn *hcon)
3918{
3919 struct l2cap_conn *conn = hcon->l2cap_data;
3920
3921 BT_DBG("hcon %p", hcon);
3922
3923 if (hcon->type != ACL_LINK || !conn)
3924 return 0x13;
3925
3926 return conn->disc_reason;
3927}
3928
3929static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930{
3931 BT_DBG("hcon %p reason %d", hcon, reason);
3932
Ville Tervoacd7d372011-02-10 22:38:49 -03003933 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03003934 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935
3936 l2cap_conn_del(hcon, bt_err(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02003937
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938 return 0;
3939}
3940
Gustavo F. Padovan43434782011-04-12 18:31:57 -03003941static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01003942{
Gustavo F. Padovan43434782011-04-12 18:31:57 -03003943 struct sock *sk = chan->sk;
3944
Gustavo F. Padovanbd3c9e22010-05-01 16:15:42 -03003945 if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM)
Marcel Holtmann255c7602009-02-04 21:07:19 +01003946 return;
3947
Marcel Holtmannf62e4322009-01-15 21:58:44 +01003948 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03003949 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Marcel Holtmannf62e4322009-01-15 21:58:44 +01003950 l2cap_sock_clear_timer(sk);
3951 l2cap_sock_set_timer(sk, HZ * 5);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03003952 } else if (chan->sec_level == BT_SECURITY_HIGH)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01003953 __l2cap_sock_close(sk, ECONNREFUSED);
3954 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03003955 if (chan->sec_level == BT_SECURITY_MEDIUM)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01003956 l2cap_sock_clear_timer(sk);
3957 }
3958}
3959
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01003960static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961{
Marcel Holtmann40be4922008-07-14 20:13:50 +02003962 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003963 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964
Marcel Holtmann01394182006-07-03 10:02:46 +02003965 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02003967
Linus Torvalds1da177e2005-04-16 15:20:36 -07003968 BT_DBG("conn %p", conn);
3969
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003970 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003972 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003973 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003974
Linus Torvalds1da177e2005-04-16 15:20:36 -07003975 bh_lock_sock(sk);
3976
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03003977 if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01003978 bh_unlock_sock(sk);
3979 continue;
3980 }
3981
Marcel Holtmannf62e4322009-01-15 21:58:44 +01003982 if (!status && (sk->sk_state == BT_CONNECTED ||
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01003983 sk->sk_state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03003984 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02003985 bh_unlock_sock(sk);
3986 continue;
3987 }
3988
Marcel Holtmannb1235d72008-07-14 20:13:54 +02003989 if (sk->sk_state == BT_CONNECT) {
3990 if (!status) {
3991 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003992 req.scid = cpu_to_le16(chan->scid);
3993 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02003994
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03003995 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03003996 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02003997
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03003998 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02003999 L2CAP_CONN_REQ, sizeof(req), &req);
4000 } else {
4001 l2cap_sock_clear_timer(sk);
4002 l2cap_sock_set_timer(sk, HZ / 10);
4003 }
4004 } else if (sk->sk_state == BT_CONNECT2) {
4005 struct l2cap_conn_rsp rsp;
4006 __u16 result;
4007
4008 if (!status) {
4009 sk->sk_state = BT_CONFIG;
4010 result = L2CAP_CR_SUCCESS;
4011 } else {
4012 sk->sk_state = BT_DISCONN;
4013 l2cap_sock_set_timer(sk, HZ / 10);
4014 result = L2CAP_CR_SEC_BLOCK;
4015 }
4016
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004017 rsp.scid = cpu_to_le16(chan->dcid);
4018 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004019 rsp.result = cpu_to_le16(result);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02004020 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004021 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4022 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 }
4024
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 bh_unlock_sock(sk);
4026 }
4027
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004028 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004029
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030 return 0;
4031}
4032
4033static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4034{
4035 struct l2cap_conn *conn = hcon->l2cap_data;
4036
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004037 if (!conn)
4038 conn = l2cap_conn_add(hcon, 0);
4039
4040 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 goto drop;
4042
4043 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4044
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004045 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004047 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004048 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 int len;
4050
4051 if (conn->rx_len) {
4052 BT_ERR("Unexpected start frame (len %d)", skb->len);
4053 kfree_skb(conn->rx_skb);
4054 conn->rx_skb = NULL;
4055 conn->rx_len = 0;
4056 l2cap_conn_unreliable(conn, ECOMM);
4057 }
4058
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004059 /* Start fragment always begin with Basic L2CAP header */
4060 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 BT_ERR("Frame is too short (len %d)", skb->len);
4062 l2cap_conn_unreliable(conn, ECOMM);
4063 goto drop;
4064 }
4065
4066 hdr = (struct l2cap_hdr *) skb->data;
4067 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004068 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069
4070 if (len == skb->len) {
4071 /* Complete frame received */
4072 l2cap_recv_frame(conn, skb);
4073 return 0;
4074 }
4075
4076 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4077
4078 if (skb->len > len) {
4079 BT_ERR("Frame is too long (len %d, expected len %d)",
4080 skb->len, len);
4081 l2cap_conn_unreliable(conn, ECOMM);
4082 goto drop;
4083 }
4084
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004085 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004086
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004087 if (chan && chan->sk) {
4088 struct sock *sk = chan->sk;
4089
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004090 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004091 BT_ERR("Frame exceeding recv MTU (len %d, "
4092 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004093 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004094 bh_unlock_sock(sk);
4095 l2cap_conn_unreliable(conn, ECOMM);
4096 goto drop;
4097 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004098 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004099 }
4100
Linus Torvalds1da177e2005-04-16 15:20:36 -07004101 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b302009-04-20 01:31:08 -03004102 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4103 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 goto drop;
4105
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004106 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004107 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108 conn->rx_len = len - skb->len;
4109 } else {
4110 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4111
4112 if (!conn->rx_len) {
4113 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4114 l2cap_conn_unreliable(conn, ECOMM);
4115 goto drop;
4116 }
4117
4118 if (skb->len > conn->rx_len) {
4119 BT_ERR("Fragment is too long (len %d, expected %d)",
4120 skb->len, conn->rx_len);
4121 kfree_skb(conn->rx_skb);
4122 conn->rx_skb = NULL;
4123 conn->rx_len = 0;
4124 l2cap_conn_unreliable(conn, ECOMM);
4125 goto drop;
4126 }
4127
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004128 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004129 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130 conn->rx_len -= skb->len;
4131
4132 if (!conn->rx_len) {
4133 /* Complete frame received */
4134 l2cap_recv_frame(conn, conn->rx_skb);
4135 conn->rx_skb = NULL;
4136 }
4137 }
4138
4139drop:
4140 kfree_skb(skb);
4141 return 0;
4142}
4143
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004144static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004146 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004148 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004150 list_for_each_entry(c, &chan_list, global_l) {
4151 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004153 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 +01004154 batostr(&bt_sk(sk)->src),
4155 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004156 sk->sk_state, __le16_to_cpu(c->psm),
4157 c->scid, c->dcid, c->imtu, c->omtu,
4158 c->sec_level, c->mode);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004159 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004161 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004162
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004163 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164}
4165
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004166static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4167{
4168 return single_open(file, l2cap_debugfs_show, inode->i_private);
4169}
4170
4171static const struct file_operations l2cap_debugfs_fops = {
4172 .open = l2cap_debugfs_open,
4173 .read = seq_read,
4174 .llseek = seq_lseek,
4175 .release = single_release,
4176};
4177
4178static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180static struct hci_proto l2cap_hci_proto = {
4181 .name = "L2CAP",
4182 .id = HCI_PROTO_L2CAP,
4183 .connect_ind = l2cap_connect_ind,
4184 .connect_cfm = l2cap_connect_cfm,
4185 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004186 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004187 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188 .recv_acldata = l2cap_recv_acldata
4189};
4190
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004191int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192{
4193 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004194
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004195 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 if (err < 0)
4197 return err;
4198
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004199 _busy_wq = create_singlethread_workqueue("l2cap");
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004200 if (!_busy_wq) {
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004201 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004202 goto error;
4203 }
4204
4205 err = hci_register_proto(&l2cap_hci_proto);
4206 if (err < 0) {
4207 BT_ERR("L2CAP protocol registration failed");
4208 bt_sock_unregister(BTPROTO_L2CAP);
4209 goto error;
4210 }
4211
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004212 if (bt_debugfs) {
4213 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4214 bt_debugfs, NULL, &l2cap_debugfs_fops);
4215 if (!l2cap_debugfs)
4216 BT_ERR("Failed to create L2CAP debug file");
4217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219 return 0;
4220
4221error:
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004222 destroy_workqueue(_busy_wq);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004223 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224 return err;
4225}
4226
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004227void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004228{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004229 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004231 flush_workqueue(_busy_wq);
4232 destroy_workqueue(_busy_wq);
4233
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4235 BT_ERR("L2CAP protocol unregistration failed");
4236
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004237 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238}
4239
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004240module_param(disable_ertm, bool, 0644);
4241MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");